【问题标题】:How to navigate the Content Presenter in the Child View Model?如何在子视图模型中导航 Content Presenter?
【发布时间】:2021-07-05 08:56:05
【问题描述】:

目标

我的实际目标是导航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";
    }
}

问题

通过内部(子)视图模型导航的正确实现是什么?

【问题讨论】:

    标签: c# mvvm


    【解决方案1】:

    您必须在MainViewModel 中实现INotifyPropertyChanged,并将名为SelectedItem 的属性添加到bindlistview

    我把代码放在下面。代码运行正常。

    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;
       }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-02-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多