在 MainWindows 和 UserControl 之间共享 DataContext
Share DataContext between MainWindows and UserControl
我想知道是否可以在 Windows 和 C#/WPF 中的 UserControl 之间共享数据上下文。
我有一个像这样的主要windows(未完成):
MainWindow.xaml:
<Window x:Class="MyProject.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MyProject"
xmlns:v="clr-namespace:MyProject.Views"
mc:Ignorable="d"
Title="MyProject" >
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
<Grid>
<v:GenerateView/>
<v:ReadView/>
</Grid>
</Window>
MainViewModel.cs:
public class MainViewModel : ViewModelBase
{
#region Properties
#endregion
#region Fields
#endregion
#region Constructor
public MainViewModel()
: base()
{
}
#endregion
#region Methods
#endregion
#region Commands
#endregion
}
根据将来的参数,我将显示我的视图 GenerateView 或 ReadView。实际上我正在开发 UserControl GenerateView,但我想知道我是否可以使用相同的 Datacontext。
根据that post,我是这样开始的:
<UserControl x:Class="MyProject.Views.GenerateView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MyProject.Views"
xmlns:p="clr-namespace:MyProject.Properties"
xmlns:MyProject="clr-namespace:MyProject"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
DataContext="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type MyProject:MainWindow}}}">
<Grid>
</Grid>
</UserControl>
但是它不起作用,当我尝试访问 GenerateView
中的 Datacontext 时,它是空的。
编辑:
我忘记了部分代码:
public partial class GenerateView : UserControl
{
private MainViewModel Context
{
get
{
return DataContext as MainViewModel;
}
}
public GenerateView()
{
InitializeComponent();
Context.PropertyChanged += Context_PropertyChanged;
}
private void Context_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
//Action to perform
}
}
行 Context.PropertyChanged += Context_PropertyChanged;
抛出异常,因为 Datacontext 为空。
根据 Andrew 的评论,我找到了解决问题的方法:
public 部分 class 生成视图:用户控件
{
私有 MainViewModel 上下文
{
得到
{
return DataContext 作为 MainViewModel;
}
}
public GenerateView()
{
InitializeComponent();
DataContextChanged += GenerateView_DataContextChanged;
}
private void GenerateView_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (Context != null)
Context.PropertyChanged += Context_PropertyChanged;
}
private void Context_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
//Action to perform
}
}
然后我从我的 UserControl 中删除了 DataContext="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type MyProject:MainWindow}}}"
。
为 Window 重用视图模型及其子用户控件背后的主要要求是什么?
这没有意义。两者有共同点吗?
在我看来,创建一个 MainWindowViewModel
并创建 SubViewModel
以供用户控制。
在 MainWindowViewModel 中创建子视图模型的实例并使用 DataContext.SubViewModel
.
访问它们
通过这样做,您可以很好地维护代码和应用程序,并保持编码标准并拥有一个没有复杂性的视图模型。如果您只是为了可重用性而混淆所有内容,您可能会违反 MVVM 模式。让不同的 views/windows 拥有自己的视图模型,因为它们完全不同。
如果两者相似,那么您可以使用 Dependency Properties
.
创建可重复使用的控件
我通常在 Window
中设置 DataContext
:
public class MainWindow : Window
{
InitializeComponent();
ViewModel vm = new ViewModel();
this.DataContext = vm;
}
或有时更高级:
我向我的 ViewModel 添加静态 属性:
public static ViewModel Instance {get; set;}
public class MainWindow : Window
{
InitializeComponent();
if(ViewModel.Instance == null)
{
ViewModel.Instance = new ViewModel();
}
this.DataContext = ViewModel.Instance;
}
可以使用视图优先的方法。
您首先要为设计目的定义一个设计上下文。
<UserControl x:Class="MyProject.Views.CustomView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MyProject.Views"
xmlns:p="clr-namespace:MyProject.Properties"
xmlns:MyProject="clr-namespace:MyProject"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance Type=vm:MyViewModel}"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
.....
</Grid>
</UserControl>
然后将用户控件绑定到主窗口的数据上下文
<Window x:Class="MyProject.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MyProject"
xmlns:v="clr-namespace:MyProject.Views"
mc:Ignorable="d"
Title="MyProject" >
<Window.DataContext>
<local:MyViewModel/>
</Window.DataContext>
<Grid>
<v:CustomView/>
</Grid>
</Window>
那么用户控件将自动继承其父控件的数据上下文。
我想知道是否可以在 Windows 和 C#/WPF 中的 UserControl 之间共享数据上下文。
我有一个像这样的主要windows(未完成):
MainWindow.xaml:
<Window x:Class="MyProject.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MyProject"
xmlns:v="clr-namespace:MyProject.Views"
mc:Ignorable="d"
Title="MyProject" >
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
<Grid>
<v:GenerateView/>
<v:ReadView/>
</Grid>
</Window>
MainViewModel.cs:
public class MainViewModel : ViewModelBase
{
#region Properties
#endregion
#region Fields
#endregion
#region Constructor
public MainViewModel()
: base()
{
}
#endregion
#region Methods
#endregion
#region Commands
#endregion
}
根据将来的参数,我将显示我的视图 GenerateView 或 ReadView。实际上我正在开发 UserControl GenerateView,但我想知道我是否可以使用相同的 Datacontext。
根据that post,我是这样开始的:
<UserControl x:Class="MyProject.Views.GenerateView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MyProject.Views"
xmlns:p="clr-namespace:MyProject.Properties"
xmlns:MyProject="clr-namespace:MyProject"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
DataContext="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type MyProject:MainWindow}}}">
<Grid>
</Grid>
</UserControl>
但是它不起作用,当我尝试访问 GenerateView
中的 Datacontext 时,它是空的。
编辑:
我忘记了部分代码:
public partial class GenerateView : UserControl
{
private MainViewModel Context
{
get
{
return DataContext as MainViewModel;
}
}
public GenerateView()
{
InitializeComponent();
Context.PropertyChanged += Context_PropertyChanged;
}
private void Context_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
//Action to perform
}
}
行 Context.PropertyChanged += Context_PropertyChanged;
抛出异常,因为 Datacontext 为空。
根据 Andrew 的评论,我找到了解决问题的方法:
public 部分 class 生成视图:用户控件 { 私有 MainViewModel 上下文 { 得到 { return DataContext 作为 MainViewModel; } }
public GenerateView()
{
InitializeComponent();
DataContextChanged += GenerateView_DataContextChanged;
}
private void GenerateView_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (Context != null)
Context.PropertyChanged += Context_PropertyChanged;
}
private void Context_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
//Action to perform
}
}
然后我从我的 UserControl 中删除了 DataContext="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type MyProject:MainWindow}}}"
。
为 Window 重用视图模型及其子用户控件背后的主要要求是什么? 这没有意义。两者有共同点吗?
在我看来,创建一个 MainWindowViewModel
并创建 SubViewModel
以供用户控制。
在 MainWindowViewModel 中创建子视图模型的实例并使用 DataContext.SubViewModel
.
通过这样做,您可以很好地维护代码和应用程序,并保持编码标准并拥有一个没有复杂性的视图模型。如果您只是为了可重用性而混淆所有内容,您可能会违反 MVVM 模式。让不同的 views/windows 拥有自己的视图模型,因为它们完全不同。
如果两者相似,那么您可以使用 Dependency Properties
.
我通常在 Window
中设置 DataContext
:
public class MainWindow : Window
{
InitializeComponent();
ViewModel vm = new ViewModel();
this.DataContext = vm;
}
或有时更高级:
我向我的 ViewModel 添加静态 属性:
public static ViewModel Instance {get; set;}
public class MainWindow : Window
{
InitializeComponent();
if(ViewModel.Instance == null)
{
ViewModel.Instance = new ViewModel();
}
this.DataContext = ViewModel.Instance;
}
可以使用视图优先的方法。 您首先要为设计目的定义一个设计上下文。
<UserControl x:Class="MyProject.Views.CustomView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MyProject.Views"
xmlns:p="clr-namespace:MyProject.Properties"
xmlns:MyProject="clr-namespace:MyProject"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance Type=vm:MyViewModel}"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
.....
</Grid>
</UserControl>
然后将用户控件绑定到主窗口的数据上下文
<Window x:Class="MyProject.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MyProject"
xmlns:v="clr-namespace:MyProject.Views"
mc:Ignorable="d"
Title="MyProject" >
<Window.DataContext>
<local:MyViewModel/>
</Window.DataContext>
<Grid>
<v:CustomView/>
</Grid>
</Window>
那么用户控件将自动继承其父控件的数据上下文。