我正在尝试为UserControl创建复合DataContext
。基本上我有一个具有Order
和Package
属性的控件,我想在XAML而不是代码中创建表示此数据源的复合对象。
这就是我尝试显示UserControl(并创建DataContext)的方法:
<views:PackageDetailsControl>
<views:PackageDetailsControl.DataContext>
<vm:OrderPackagePair Package="{Binding Package, Mode=OneWay}"
Order="{Binding Order, Mode=OneWay}"/>
</views:PackageDetailsControl.DataContext>
</views:PackageDetailsControl>
OrderPackagePair
对象是在XAML中创建的简单依赖项对象:
public class OrderPackagePair : DependencyObject
{
public OrderDetails Order
{
get { return (OrderDetails)GetValue(OrderProperty); }
set { SetValue(OrderProperty, value); }
}
public static readonly DependencyProperty OrderProperty =
DependencyProperty.Register("Order", typeof(OrderDetails), typeof(OrderPackagePair), new UIPropertyMetadata(null));
public PackageInfo Package
{
get { return (PackageInfo)GetValue(PackageProperty); }
set { SetValue(PackageProperty, value); }
}
public static readonly DependencyProperty PackageProperty =
DependencyProperty.Register("Package", typeof(PackageInfo), typeof(OrderPackagePair), new UIPropertyMetadata(null));
}
Order
和Package
没有正确绑定,只是空。
是的我知道可能有更好的方法 - 但我无法理解为什么这不起作用。偶尔在Blend中它会工作然后再次变为空白。
答案 0 :(得分:1)
这不起作用,因为DependencyObject
(OrderPackagePair
类)不监视其依赖项属性的内部更改。由于OrderPackagePair对象保持不变,因此DataContext被视为未更改。
在相反的站点上,类Freezable
旨在通知订户当其中一个依赖项属性发生更改时实例已更改。
因此,请尝试将Freezable
而不是DependencyObject
声明为OrderPackagePair
的基类。
-------------更新--------
是的,它有效。为了证明这一点,我已经实现了简单的例子。
OrderPackagePairClass代码:
public class OrderPackagePair : Freezable
{
public OrderDetails Order
{
get { return (OrderDetails)GetValue(OrderProperty); }
set { SetValue(OrderProperty, value); }
}
public static readonly DependencyProperty OrderProperty =
DependencyProperty.Register("Order", typeof(OrderDetails), typeof(OrderPackagePair), new UIPropertyMetadata(null));
public PackageInfo Package
{
get { return (PackageInfo)GetValue(PackageProperty); }
set { SetValue(PackageProperty, value); }
}
public static readonly DependencyProperty PackageProperty =
DependencyProperty.Register("Package", typeof(PackageInfo), typeof(OrderPackagePair), new UIPropertyMetadata(null));
protected override Freezable CreateInstanceCore()
{
throw new NotImplementedException();
}
}
XAML:
<Window x:Class="WindowTest.MainWindow"
xmlns:self="clr-namespace:WindowTest"
Name="RootControl">
<StackPanel Margin="10" DataContextChanged="StackPanel_DataContextChanged">
<StackPanel.DataContext>
<self:OrderPackagePair Package="{Binding Path=DataContext.PackageInfo, Mode=OneWay, ElementName=RootControl}"
Order="{Binding Path=DataContext.OrderDetails, Mode=OneWay, ElementName=RootControl}"/>
</StackPanel.DataContext>
<Button Margin="10" Content="Change Package" Click="Button_Click"/>
</StackPanel>
</Window>
代码背后:
public partial class MainWindow : Window, INotifyPropertyChanged
{
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
}
private OrderDetails _orderDetails;
public OrderDetails OrderDetails
{
get
{
return this._orderDetails;
}
set
{
this._orderDetails = value;
this.OnPropertyChanged("OrderDetails");
}
}
private PackageInfo _packageInfo;
public PackageInfo PackageInfo
{
get
{
return this._packageInfo;
}
set
{
this._packageInfo = value;
this.OnPropertyChanged("PackageInfo");
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
this.PackageInfo = new PackageInfo(DateTime.Now.ToString());
}
private void StackPanel_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
Trace.WriteLine("StackPanel.DataContext changed");
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
var safeEvent = this.PropertyChanged;
if (safeEvent != null)
{
safeEvent(this, new PropertyChangedEventArgs(name));
}
}
}
当您单击按钮时,模型更改PackageInfo属性(为简单模型和视图在同一个类中实现)。依赖属性OrderPackagePair.Package对新值作出反应并覆盖其值。由于Freezable性质,OrderPackagePair会通知所有订阅者它已被更改并调用处理程序StackPanel_DataContextChanged。如果你回到DependencyObject作为OrderPackagePair的基类 - 将永远不会调用handler。
所以,我认为你的代码因其他错误而无效。您应该仔细使用DataContext。例如,您写道:
<views:PackageDetailsControl>
<views:PackageDetailsControl.DataContext>
<vm:OrderPackagePair Package="{Binding Package, Mode=OneWay}"
Order="{Binding Order, Mode=OneWay}"/>
</views:PackageDetailsControl.DataContext>
</views:PackageDetailsControl>
当然这是其中一个问题。绑定表达式面向当前的DataContext。但是您将DataContext设置为OrderPackagePair实例。所以你将OrderPackagePair.Package绑定到OrderPackagePair.Package(我想,你的目标是将OrderPackagePair.Package绑定到Model.Package)。这就是为什么没有发生的原因。
在我的绑定表达式示例中,我明确告诉我要绑定哪个DataContext:
Package="{Binding Path=DataContext.PackageInfo, Mode=OneWay, ElementName=RootControl}"