是否可以在一个UserControl中有两个不同的DataContext
?我想访问我的Model
个对象之一,还要访问MainViewModel中的属性。例子:
ClassDatas DataContext
(模型中定义的对象):
<DataGrid x:Name="PropertiesControl1" Height="auto" ItemsSource="{Binding ClassDatas}" HeadersVisibility="None" AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="True">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Fields}" Header="" Width="*" IsReadOnly="True"/>
</DataGrid.Columns>
</DataGrid>
MainViewModel DataContext
:
<TextBox x:Name="txtFields" Text="{Binding FieldsTextProperty, UpdateSourceTrigger=PropertyChanged}" Height="23" TextWrapping="NoWrap" Background="#FFCBEECD" AcceptsReturn="False" >.....</TextBox>
进一步如何将它们结合起来呢?
<TextBox x:Name="txtFields" Text="{Binding FieldsTextProperty, UpdateSourceTrigger=PropertyChanged}" Height="23" TextWrapping="NoWrap" Background="#FFCBEECD" AcceptsReturn="False" >
<i:Interaction.Triggers>
<iex:KeyTrigger Key="Enter">
<cmd:EventToCommand Command="{Binding DataContext.AddFieldCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" PassEventArgsToCommand="True"/>
</iex:KeyTrigger>
</i:Interaction.Triggers>
</TextBox>
FieldsTextProperty
是来自DataContext
的{{1}},MainViewModel
来自我的对象的EventToCommand
。
答案 0 :(得分:0)
是的,您的用户控件可以拥有DataContext,并且该用户控件中的任何控件也可以具有不同的DataContext,但在您的场景中不是您应该执行的操作。
您的TextBox应该使用绑定到UserControl的基础ViewModel的简单命令,并且在执行命令时,您应该使用消息总线从MainViewModel或任何其他ViewModel获取所需的任何内容。消息总线是ViewModels应该如何在MVVM中进行通信和交换信息......
答案 1 :(得分:0)
不,控件只能将单个对象设置为其DataContext
属性
但是绑定不会 绑定到它的DataContext
。您可以使用其他绑定属性为绑定指定不同的源。用于更改绑定源的常用属性是Source
,RelativeSource
和ElementName
。
您可以更改特定绑定的绑定源,例如您在Command
绑定
或者您可以通过将控件的DataContext
属性设置或绑定到其他内容来为整个控件更改
我实际上在WPF初学者的DataContext
看到了很多混乱,我写了一篇关于它的博客文章。您可能有兴趣阅读它:What is this "DataContext" you speak of?
这是我用来帮助演示DataContext
:
假设我们将窗口绑定到名为
ClassA
的对象。ClassA
有一个名为ClassB
的属性,ClassA
和ClassB
都有一个名为Name
的属性。这是一个XAML块,它说明了DataContext的工作原理。它还包含一个控件如何引用不在其自己的DataContext中的属性的示例。
public partial class MyWindow: Window
{
public MyWindow()
{
InitializeComponent();
this.DataContext = new ClassA();
}
}
public class ClassA
{
public string Name { get; set; }
public ClassB ClassB { get; set; }
}
public class ClassB
{
public string Name { get; set; }
}
<!-- DataContext set to ClassA in initialization code -->
<Window x:Name="MyWindow">
<!-- DataContext here is not specified, so it's inherited
from its parent's DataContext, which is ClassA -->
<StackPanel>
<!-- DataContext inherited from parent, which is
ClassA, so this will display ClassA.Name -->
<Label Content="{Binding Name}" />
<!-- DataContext is still ClassA, however we are
setting it to ClassA.ClassB with a binding -->
<StackPanel DataContext="{Binding ClassB}">
<!-- DataContext inherited from parent, which is
ClassB, so this will display ClassB.Name -->
<Label Content="{Binding Name}" />
<!-- DataContext is still ClassB, but we are
binding to the Window's DataContext.Name,
which is ClassA.Name -->
<Label Content="{Binding
ElementName=MyWindow,
Path=DataContext.Name}" />
</StackPanel>
<!-- We've left the StackPanel with its DataContext
bound to ClassB, so this Label's DataContext
is ClassA (inherited from parent StackPanel),
and we are binding to ClassA.ClassB.Name -->
<Label Content="{Binding ClassB.Name}" />
</StackPanel>
</Window>