如何在子视图模型中导航内容展示器?
How to navigate the Content Presenter in the Child View Model?
目标
我的实际目标是导航 ContentPresenter
不是通过主导航,而是通过导航页面中的按钮。
我目前的成绩
这是我左侧的主导航:
单击任一主要导航项时,ContentPresenter
将加载它的 ViewModel。
这是 Home
选项卡
和Some Other tab
预期结果
我的期望是从加载的视图模型中单击按钮(见下图),然后导航到另一个视图模型...
但我不确定如何实现这样的想法。
代码
页面视图模型
public class PageViewModel
{
public string Title { get; set; }
public object Content { get; set; }
public List<PageViewModel> Children { get; set; }
}
主视图模型
public class MainViewModel
{
public List<PageViewModel> Navigation { get; set; }
public MainViewModel()
{
Navigation = new List<PageViewModel>
{
new PageViewModel
{
Title = "Home",
Content = new HomeViewModel()
},
new PageViewModel
{
Title = "Some Other Tab",
Content = new SomeOtherViewModel()
}
};
}
}
MainWindow.xaml
...
<Window.DataContext>
<local:MainViewModel />
</Window.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<StackPanel>
<ListView ItemsSource="{Binding Navigation}"
x:Name="Nav">
<ListView.ItemTemplate>
<DataTemplate DataType="{x:Type local:PageViewModel}">
<TextBlock Text="{Binding Title}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
<ContentPresenter Content="{Binding ElementName=Nav, Path=SelectedItem.Content}"
Grid.Column="1"/>
</Grid>
</Window>
主视图模型
public class HomeViewModel
{
public string SomeTitle { get; set; }
public HomeViewModel()
{
SomeTitle = "Hello Home ViewModel";
}
}
一些其他视图模型
public class SomeOtherViewModel
{
public string SomeTitle { get; set; }
public SomeOtherViewModel()
{
SomeTitle = "Hello SomeOther View Model";
}
}
问题
通过内部(子)视图模型导航的正确实现是什么?
您必须在 MainViewModel
中实现 INotifyPropertyChanged
并在 listview
中添加一个名为 SelectedItem
到 bind
的 属性。
我把执行此操作的代码放在下面。代码运行正常。
PageViewModel.cs
public class PageViewModel
{
public string Title { get; set; }
public object Content { get; set; }
}
MainViewModel.cs
public class MainViewModel : INotifyPropertyChanged
{
public List<PageViewModel> Navigation { get; set; }
private PageViewModel selectedItem { get; set; }
public PageViewModel SelectedItem
{
get { return selectedItem; }
set
{
selectedItem = value;
OnPropertyChanged("SelectedItem");
}
}
public MainViewModel()
{
Navigation = new List<PageViewModel>
{
new PageViewModel
{
Title = "Home",
Content = new HomeViewModel(this),
},
new PageViewModel
{
Title = "Some Other Tab",
Content = new SomeOtherViewModel(),
}
};
SelectedItem = Navigation.FirstOrDefault();
}
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
HomeViewModel.cs
public class HomeViewModel
{
public string SomeTitle { get; set; }
public object View { get; set; }
MainViewModel mainViewModel;
public RelayCommand SomeOtherCommand { get; private set; }
public HomeViewModel(MainViewModel _mainViewModel)
{
SomeTitle = "Hello Home ViewModel";
View = new View1(this);
mainViewModel = _mainViewModel;
SomeOtherCommand = new RelayCommand(SomeOtherMethod);
}
private void SomeOtherMethod(object parameter)
{
mainViewModel.SelectedItem = mainViewModel.Navigation.Where(a => a.Title == "Some Other Tab").FirstOrDefault();
}
}
SomeOtherViewModel.cs
public class SomeOtherViewModel
{
public string SomeTitle { get; set; }
public object View { get; set; }
public SomeOtherViewModel()
{
SomeTitle = "Hello SomeOther View Model";
View = new View2();
}
}
RelayCommand.cs
public class RelayCommand : ICommand
{
readonly Action<object> _execute;
readonly Predicate<object> _canExecute;
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
{
throw new NullReferenceException("execute");
}
else
{
_execute = execute;
_canExecute = canExecute;
}
}
public event EventHandler CanExecuteChanged;
public void RaiseCanExecuteChanged()
{
if (CanExecuteChanged != null)
CanExecuteChanged(this, EventArgs.Empty);
}
public RelayCommand(Action<object> execute) : this(execute, null)
{
}
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
public void Execute(object parameter)
{
_execute.Invoke(parameter);
}
}
MainWindow.xaml
<Window.DataContext>
<local:MainViewModel />
</Window.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<StackPanel>
<ListView ItemsSource="{Binding Navigation}" x:Name="Nav" SelectedItem="{Binding Path=SelectedItem,Mode=TwoWay}">
<ListView.ItemTemplate>
<DataTemplate DataType="{x:Type local:PageViewModel}">
<TextBlock Text="{Binding Title}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
<ContentPresenter Content="{Binding ElementName=Nav, Path=SelectedItem.Content.View}" Grid.Column="1" />
</Grid>
View1.xaml
<Grid>
<Button x:Name="btnGet" Content="get" Height="40" Command="{Binding SomeOtherCommand}"></Button>
</Grid>
View2.xaml
<Grid>
<Button Content="test"></Button>
</Grid>
View1.cs
public partial class View1 : UserControl
{
public View1(HomeViewModel homeViewModel)
{
InitializeComponent();
DataContext = homeViewModel;
}
}
目标
我的实际目标是导航 ContentPresenter
不是通过主导航,而是通过导航页面中的按钮。
我目前的成绩
这是我左侧的主导航:
单击任一主要导航项时,ContentPresenter
将加载它的 ViewModel。
这是 Home
选项卡
和Some Other tab
预期结果
我的期望是从加载的视图模型中单击按钮(见下图),然后导航到另一个视图模型...
但我不确定如何实现这样的想法。
代码
页面视图模型
public class PageViewModel
{
public string Title { get; set; }
public object Content { get; set; }
public List<PageViewModel> Children { get; set; }
}
主视图模型
public class MainViewModel
{
public List<PageViewModel> Navigation { get; set; }
public MainViewModel()
{
Navigation = new List<PageViewModel>
{
new PageViewModel
{
Title = "Home",
Content = new HomeViewModel()
},
new PageViewModel
{
Title = "Some Other Tab",
Content = new SomeOtherViewModel()
}
};
}
}
MainWindow.xaml
...
<Window.DataContext>
<local:MainViewModel />
</Window.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<StackPanel>
<ListView ItemsSource="{Binding Navigation}"
x:Name="Nav">
<ListView.ItemTemplate>
<DataTemplate DataType="{x:Type local:PageViewModel}">
<TextBlock Text="{Binding Title}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
<ContentPresenter Content="{Binding ElementName=Nav, Path=SelectedItem.Content}"
Grid.Column="1"/>
</Grid>
</Window>
主视图模型
public class HomeViewModel
{
public string SomeTitle { get; set; }
public HomeViewModel()
{
SomeTitle = "Hello Home ViewModel";
}
}
一些其他视图模型
public class SomeOtherViewModel
{
public string SomeTitle { get; set; }
public SomeOtherViewModel()
{
SomeTitle = "Hello SomeOther View Model";
}
}
问题
通过内部(子)视图模型导航的正确实现是什么?
您必须在 MainViewModel
中实现 INotifyPropertyChanged
并在 listview
中添加一个名为 SelectedItem
到 bind
的 属性。
我把执行此操作的代码放在下面。代码运行正常。
PageViewModel.cs
public class PageViewModel
{
public string Title { get; set; }
public object Content { get; set; }
}
MainViewModel.cs
public class MainViewModel : INotifyPropertyChanged
{
public List<PageViewModel> Navigation { get; set; }
private PageViewModel selectedItem { get; set; }
public PageViewModel SelectedItem
{
get { return selectedItem; }
set
{
selectedItem = value;
OnPropertyChanged("SelectedItem");
}
}
public MainViewModel()
{
Navigation = new List<PageViewModel>
{
new PageViewModel
{
Title = "Home",
Content = new HomeViewModel(this),
},
new PageViewModel
{
Title = "Some Other Tab",
Content = new SomeOtherViewModel(),
}
};
SelectedItem = Navigation.FirstOrDefault();
}
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
HomeViewModel.cs
public class HomeViewModel
{
public string SomeTitle { get; set; }
public object View { get; set; }
MainViewModel mainViewModel;
public RelayCommand SomeOtherCommand { get; private set; }
public HomeViewModel(MainViewModel _mainViewModel)
{
SomeTitle = "Hello Home ViewModel";
View = new View1(this);
mainViewModel = _mainViewModel;
SomeOtherCommand = new RelayCommand(SomeOtherMethod);
}
private void SomeOtherMethod(object parameter)
{
mainViewModel.SelectedItem = mainViewModel.Navigation.Where(a => a.Title == "Some Other Tab").FirstOrDefault();
}
}
SomeOtherViewModel.cs
public class SomeOtherViewModel
{
public string SomeTitle { get; set; }
public object View { get; set; }
public SomeOtherViewModel()
{
SomeTitle = "Hello SomeOther View Model";
View = new View2();
}
}
RelayCommand.cs
public class RelayCommand : ICommand
{
readonly Action<object> _execute;
readonly Predicate<object> _canExecute;
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
{
throw new NullReferenceException("execute");
}
else
{
_execute = execute;
_canExecute = canExecute;
}
}
public event EventHandler CanExecuteChanged;
public void RaiseCanExecuteChanged()
{
if (CanExecuteChanged != null)
CanExecuteChanged(this, EventArgs.Empty);
}
public RelayCommand(Action<object> execute) : this(execute, null)
{
}
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
public void Execute(object parameter)
{
_execute.Invoke(parameter);
}
}
MainWindow.xaml
<Window.DataContext>
<local:MainViewModel />
</Window.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<StackPanel>
<ListView ItemsSource="{Binding Navigation}" x:Name="Nav" SelectedItem="{Binding Path=SelectedItem,Mode=TwoWay}">
<ListView.ItemTemplate>
<DataTemplate DataType="{x:Type local:PageViewModel}">
<TextBlock Text="{Binding Title}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
<ContentPresenter Content="{Binding ElementName=Nav, Path=SelectedItem.Content.View}" Grid.Column="1" />
</Grid>
View1.xaml
<Grid>
<Button x:Name="btnGet" Content="get" Height="40" Command="{Binding SomeOtherCommand}"></Button>
</Grid>
View2.xaml
<Grid>
<Button Content="test"></Button>
</Grid>
View1.cs
public partial class View1 : UserControl
{
public View1(HomeViewModel homeViewModel)
{
InitializeComponent();
DataContext = homeViewModel;
}
}