我有一个包含两个不同 UserControl 的表单 - 一个包含 Telerik RadGridView,另一个包含 Telerik DataForm。
网格用户控件绑定(bind)到 ViewModel,该 ViewModel 包含一个公开网格绑定(bind)到的 Items 集合的属性。
当我将表单绑定(bind)到该属性时,一切正常。
但我需要访问表单控件中实际上不属于网格控件的 View 模型的其他信息。
所以我想我应该向表单用户控件添加一个属性,并将其绑定(bind)到项目集合:
<local:FormControl x:Name="formControl"
ItemsSource="{Binding items}"
/>
在表单的代码隐藏中,我添加了一个普通属性:
private object itemsSource;
public object ItemsSource
{
get { return this.itemsSource; }
set { this.itemsSource = value; }
}
当然,这不起作用。我收到有关必须使用 DependencyProperty 的错误。我认为这令人放心 - 该页面实际上正在尝试绑定(bind)到我认为应该的属性。
所以我将其转换为 DependencyProperty:
public static DependencyProperty ItemsSourceProperty =
DependencyProperty.Register("ItemsSource", typeof(object), typeof(FormControl));
public object ItemsSource
{
get { return GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
编译并运行没有错误。当然,除非控件的 View 模型没有任何项目。接下来是尝试将 ItemsSource 属性传递给表单控件的 View 模型:
public FormControl()
{
InitializeComponent();
this.DataContext = new FormControlVM(this.ItemsSource);
...
这没有用。构造 FormControl() 时 ItemsSource 为 null。因此,我向 View 模型添加了 setItemsSource() 方法,并在 ItemsSource 属性的 set 函数中调用它。这也行不通。 xaml 显然绑定(bind)到该属性,但它似乎没有调用属性的 set 函数即可完成此操作。
所以我决定在 DependencyProperty 上监听 ValueChanged 事件:
public FormControl()
{
InitializeComponent();
this.DataContext = new FormControlVM();
DependencyPropertyDescriptor prop =
DependencyPropertyDescriptor.FromProperty(FormControl.ItemsSourceProperty, this.GetType());
prop.AddValueChanged(this, delegate
{
FormControlVM formControlVM = (FormControlVM)this.DataContext;
formControlVM.setItemsSource(this.ItemsSource);
});
...
但它仍然不起作用。 ValueChanged 委托(delegate)似乎从未被调用。
这看起来应该是一件简单的事情,但我无法在网上找到示例,并且我已经尝试了我能想到的所有组合。
关于我应该如何处理这个问题有什么想法吗?
============ 有关绑定(bind)的附加信息 ============
Will 要求提供有关执行绑定(bind)的 xaml 的信息。
如果我将其放在包含用户控件的页面中,则将用户控件绑定(bind)到页面的 View 模型:
<local:FormControl x:Name="formControl"
Grid.Column="2"
DataContext="{Binding}"
/>
然后在用户控件中,将用户控件中的表单绑定(bind)到页面 View 模型的 itemsCollection:
<telerik:RadDataForm
ItemsSource="{Binding itemsCollection}"
Header="View Item:"
CommandButtonsVisibility="None"
AutoGenerateFields="False"
/>
然后一切正常。
但问题是我无法将用户控件绑定(bind)到页面的 View 模型。我需要让用户控件的 View 模型公开页面 View 模型不应该看到的信息。
而且我无法让用户控件中的表单到达用户控件之外,绑定(bind)到页面 View 模型上的属性。这是违反封装的,这将使在不同页面上使用用户控件变得更加复杂,并严重限制我将来修改控件内部的方式。 (页面不应该知道有关用户控件内的控件的任何信息,用户控件内的控件也不应该知道有关页面的任何信息。)
当我在页面上包含用户控件时,我希望将用户控件绑定(bind)到页面 View 模型的属性,并且希望用户控件中的任何控件绑定(bind)到用户控件或用户的属性控件的 View 模型。
我认为这是一个相当普遍的现象。但我无法找到任何如何完成此操作的示例。
最佳答案
重述问题:我有一个 UserControl,其中包含嵌入式 Telerik DataForm 控件。我需要将嵌入的 DataForm 的 ItemsSource 属性绑定(bind)到放置 UserControl 的页面的 DataContext 的属性。
如果 UserControl 没有设置其 DataContext,它将继承页面的 DataContext,并且我可以轻松地将嵌入的 DataForm 的 ItemsSource 属性绑定(bind)到它的属性,但 UserControl 有它自己的 DataContext。
如果将 UserControl 编写为仅在此页面上使用,我可以使用relativesource 绑定(bind)将嵌入的 DataForm 的 ItemsSource 属性绑定(bind)到该页面的属性。但此 UserControl 旨在在多个地方使用,并且不能对 UserControl 之外的属性具有静默依赖关系。我需要明确依赖关系。
在 UserControl 上创建 DependencyProperty 是正确的方法,但无需尝试在 UserControl 的 View 模型中复制该属性。
我需要做的是
1:向 UserControl 添加 DependencyProperty:
public QueryableCollectionView ItemsSource
{
get { return (QueryableCollectionView)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.Register("ItemsSource", typeof(QueryableCollectionView), typeof(FormControl));
注意:我不需要实现回调函数。
2:使用RelativeSource 绑定(bind)将嵌入式DataForm 的ItemsProperty 绑定(bind)到UserControl 的新DependencyProperty:
<UserControl
...>
<telerik:RadDataForm
ItemsSource="{Binding Path=ItemsSource, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"
/>
</UserControl>
3:使页面的 viewModel 可见,并具有正确的类型(DataContext 具有类型对象):
public partial class MainWindow : Window
{
public MainWIndow()
{
this.InitializeComponent();
this.DataContext = new MainWindowVM();
}
public MainWindowVM viewModel
{ get { return this.DataContext as MainWindowVM; } }
}
4:在页面上,再次使用RelativeSource 绑定(bind),将 UserControl 的新 ItemsProperty DependencyProperty 绑定(bind)到页面 View 模型的相应属性:
<Window
...>
<local:FormControl
ItemsSource="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type telerik:RadPane}},Path=viewModel.items}"
/>
</Window>
关于wpf - 绑定(bind)到 UserControl 中的 DependencyProperty,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9487352/