使用视图模型值的依赖属性

本文关键字:依赖 属性 模型 视图 | 更新日期: 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"事件,来处理你需要的任何处理。这样就不那么复杂了。

如果你坚持使用内部视图模型,那么你需要找出一种方法来分离"外部"绑定(你的控件集的消费者)和"内部"绑定(你的控件用来显示文本)。