3

我设置了一个 MVVM 来在视图之间切换。为了适应设计,MainWindow 包含一个 tabcontroller,它相应地显示一个页面。当用户按下按钮时,其中一个内页被改变。设置的可视化表示: 设置的可视化表示

我将Presenter视图模型设置为的数据上下文StudentView来处理在StudentOverview. 那行得通,但是当我想切换视图时,我必须设置一个特定类型的新数据上下文。但由于Presenter是我的数据上下文,因此切换它会删除按钮的功能。

我想要的是在不依赖数据上下文的情况下更改数据模板。

学生视图.xaml

<Page {...}>
    
    <Page.DataContext>
        <viewModels:Presenter/>
    </Page.DataContext>
    <Page.Resources>
        <DataTemplate x:Key="Overview" DataType="{x:Type models:StudentOverviewModel}">
            <local:StudentOverview/>
        </DataTemplate>
        <DataTemplate x:Key="Add" DataType="{x:Type models:StudentAddModel}">
            <local:AddStudentControl/>
        </DataTemplate>
    </Page.Resources>
    <ContentPresenter Content="{Binding}"/>
</Page>

StudentView.xaml.cs

public partial class StudentView : Page
    {
        public StudentView()
        {
            InitializeComponent();

            // This switches the view but disables the button
            this.DataContext = new StudentOverviewModel();

            if (this.DataContext is Presenter presenter)
            {
                presenter.PropertyChanged += (object o, PropertyChangedEventArgs e) =>
                {
                    // This switches the view but disables the button
                    this.DataContext = new StudentAddModel();
                };
            }
        }
    }
4

1 回答 1

2

我可以提出两种解决方案:

第一个解决方案(推荐)是向视图模型添加SelectedContent类型属性object(或所有视图模型的任何其他通用基本类型,例如IContentModelPresenter。然后将 绑定SelectedContentContentPresenter.Content属性:

演示者.cs

public partial class Presenter : INotifyPropertyChanged
{
  public Presenter()
  {
    // Set default content
    this.SelectedContent = new StudentOverviewModel();
  }

  private object selectedContent;
  public object SelectedContent
  {
    get => this.selectedContent; 
    set
    { 
      this.selectedContent = value; 
      OnPropertyChanged();
    }
  }

  // Use ICommand implementation like DelegateCommand
  public ICommand LoadContentCommand => new LoadContentCommand(ExecuteLoadContent, CanExecuteLoadContent);

  private void ExecuteLoadContent(object param)
  {
    // Do something ...

    // Load the new content on Button clicked
    this.SelectedContent = new StudentAddModel();
  }

  private bool CanExecuteLoadContent => true;
}

StudentView.xaml.cs

public partial class StudentView : Page
{
  public StudentView()
  {
    InitializeComponent();
  }
}

学生视图.xaml

<Page {...}>
  <Page.DataContext>
    <viewModels:Presenter/>
  </Page.DataContext>
  <Page.Resources>
    <DataTemplate DataType="{x:Type models:StudentOverviewModel}">
      <local:StudentOverview/>
    </DataTemplate>
    <DataTemplate ="{x:Type models:StudentAddModel}">
      <local:AddStudentControl/>
    </DataTemplate>
  </Page.Resources>

  <ContentPresenter Content="{Binding SelectedContent}"/>
</Page>

StudentOverview.xaml

<UserControl{...}>

  <!--- content -->

  <Button Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type StudentView}}, Path=DataContext.LoadContentCommand}"/>
</UserControl>

您可以安全地删除(如果不相同)的Key属性,以便它们将自动应用于任何匹配的数据类型(隐式)。DataTemplateDataTypeDataTemplate


另一种解决方案是移动SelectedContenttoStudentView并将其变成DependencyProperty

StudentView.xaml.cs

public partial class StudentView : Page
{
  public static readonly DependencyProperty SelectedContentProperty = DependencyProperty.Register(
    "SelectedContent", 
    typeof(object), 
    typeof(StudentView));

  public object SelectedContent
  {
    get => GetValue(SelectedContentProperty); 
    set => SetValue(SelectedContentProperty, value); 
  }

  public StudentView()
  {
    InitializeComponent();

    // This switches the view without disabling the button
    this.SelectedContent = new StudentOverviewModel();

    if (this.DataContext is Presenter presenter)
    {
      presenter.PropertyChanged += (object o, PropertyChangedEventArgs e) =>
      {
        // This switches the view without disabling the button
        this.SelectedContent = new StudentAddModel();               
      };
    }
  }
}

学生视图.xaml

<Page {...}>
  <Page.DataContext>
    <viewModels:Presenter/>
  </Page.DataContext>
  <Page.Resources>
    <DataTemplate DataType="{x:Type models:StudentOverviewModel}">
      <local:StudentOverview/>
    </DataTemplate>
    <DataTemplate ="{x:Type models:StudentAddModel}">
      <local:AddStudentControl/>
    </DataTemplate>
  </Page.Resources>

  <ContentPresenter Content="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type StudentView}}, Path=SelectedContent}"/>
</Page>
于 2019-11-17T13:35:33.333 回答