c# - 如何在不更改 DataContext 的情况下使内容动态化
问题描述
我设置了一个 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();
};
}
}
}
解决方案
我可以提出两种解决方案:
第一个解决方案(推荐)是向视图模型添加SelectedContent
类型属性object
(或所有视图模型的任何其他通用基本类型,例如IContentModel
)Presenter
。然后将 绑定SelectedContent
到ContentPresenter.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
属性,以便它们将自动应用于任何匹配的数据类型(隐式)。DataTemplate
DataType
DataTemplate
另一种解决方案是移动SelectedContent
toStudentView
并将其变成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>
推荐阅读
- sql - 病理插入时间
- php - 没有 outh 或 auth laravel 的社交登录
- php - Laravel If 语句未在 html 视图上返回数据
- pyspark - Pyspark - 根据时间和位置计算组中的平均速度
- c# - 使用 |DataDirectory| 后 SQL Server 数据库未更新 在 C# Windows 窗体项目中
- ios - 如何在 Mux 上上传视频文件
- arm - ARMv7 字补丁 (CBZ)
- javascript - React Native 版本不匹配 Js 版本 0.50.4 Native 版本 0.62.2
- google-fit - 从 Google Fit API 获取 .tcx 数据
- javascript - 根据对象的嵌套属性映射新数组