使用视图模型值的依赖属性
本文关键字:依赖 属性 模型 视图 | 更新日期: 2023-09-27 18:11:23
当尝试实现包含视图模型和一些依赖属性的用户控件时,我遇到了问题。
现在,我们的想法是在UC上有一个包含水印属性的文本框,允许开发人员使用它通过xaml将资源文件中的本地化字符串传递给它。
考虑到UC将不得不处理一些信息,我需要为它创建一个视图模型。
到目前为止,我所得到的如下:
在用户控件上,我有一个控件,其中包含一个名为"水印"的字符串属性,它的值绑定到我的虚拟机水印属性:
<Grid x:Name="LayoutRoot" Background="Gray">
<controls:CustomTextBox Watermark="{Binding Path=WatermarkTextValue}"/>
</Grid>
视图模型看起来像这样:
private string watermarkText;
public string WatermarkTextValue
{
get
{
return watermarkText;
}
set
{
watermarkText = value;
this.OnPropertyChanged(() => this.WatermarkTextValue);
}
}
后面的User控件代码包含依赖属性,以便将视图模型的水印绑定到资源文件项,并在构造函数中创建VM属性和依赖项之间的绑定:
public partial class SearchFilterUserControl : UserControl
{
public SearchFilterUserControl()
{
InitializeComponent();
this.DataContext = new SearchFilterViewModel();
var viewModelPropertyBinding = new Binding("WatermarkTextValue") { Mode = BindingMode.TwoWay, Source = this.DataContext };
this.SetBinding(WatermarkTextProperty, viewModelPropertyBinding);
}
public string WatermarkText
{
get
{
return (string)this.GetValue(WatermarkTextProperty);
}
set
{
this.SetValue(WatermarkTextProperty, value);
}
}
public static readonly DependencyProperty WatermarkTextProperty =
DependencyProperty.Register("WatermarkText", typeof(string), typeof(SearchFilterUserControl), new PropertyMetadata(string.Empty));
}
这里的主要问题是,当使用UC从一个视图;我只能看到xaml中硬编码的值,任何其他类型的绑定都不起作用,所以在这两行中:
<userControls:SearchFilterUserControl WatermarkText="{Binding Path=SearchFilterUserControl_SearchWatermarkText, Source={StaticResource ResourceManagementClientResources}}"/>
<userControls:SearchFilterUserControl WatermarkText="Hardcoded text"/>
我看到一个空文本框和另一个与"硬编码文本"水印在它!
这里有一些问题,但让我们从这个开始:
public SearchFilterUserControl()
{
InitializeComponent();
this.DataContext = new SearchFilterViewModel();
}
当您这样做时,您正在更改控件的数据上下文,这将破坏控件用户的任何绑定。也就是说,使用如下代码:
<controls:SearchFilterUserControl Watermark="{Binding Path=WatermarkTextValue}" />
运行时现在将在"SearchFilterViewModel"中寻找"WatermarkTextValue",这是它的新数据上下文。
解决这个问题的一种方法是将数据上下文应用于控件的子元素(通常是"LayoutRoot"或类似的元素)。这样外层的DataContext将被保留。注意,你必须在"OnApplyTemplate"覆盖中这样做——你不能在构造函数中这样做,因为模板元素还没有被加载。像这样:public SearchFilterUserControl()
{
InitializeComponent();
this.DataContext = new SearchFilterViewModel();
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
GetTemplateChild("LayoutRoot").DataContext = new SearchFilterViewModel();
}
第二个问题是,它看起来像你暴露"WatermarkTextValueProperty"作为一个绑定目标到你的控制的消费者,然后试图重新设置它作为你的内部绑定到你的视图模型的目标。这显然行不通。
我的建议是简单地抛弃视图模型,并在模板绑定中使用IValueConverter
的组合,和/或依赖属性的"changed"事件,来处理你需要的任何处理。这样就不那么复杂了。
如果你坚持使用内部视图模型,那么你需要找出一种方法来分离"外部"绑定(你的控件集的消费者)和"内部"绑定(你的控件用来显示文本)。