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

时间:2014-07-03 15:01:52

标签: c# silverlight mvvm data-binding dependency-properties

我在尝试实现包含视图模型和一些依赖项属性的用户控件时遇到了问题。

现在,我们的想法是在UC上有一个包含水印属性的文本框,允许开发人员使用它来通过xaml将资源文件中的本地化字符串传递给它。

鉴于UC必须处理一些信息,我需要为它创建一个视图模型。

到目前为止我所拥有的内容如下:

在用户控件上我有一个控件,其中包含一个名为“Watermark”的字符串属性,它的值绑定到我的VM水印属性:

<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);
            }
        }

后面的用户控件代码包含要使用的依赖项属性,以便将视图模型的水印绑定到资源文件条目,并在构造函数中创建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"/>

我看到一个空文本框和另一个带有“硬编码文字”水印的文本框!

1 个答案:

答案 0 :(得分:1)

这里有一些问题,但让我们从这开始:

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和/或依赖属性的“已更改”事件,以处理您需要的任何处理。这将是一个不那么复杂的问题。

如果您坚持使用内部视图模型,那么您需要找出一种方法来将“外部”绑定(控件的使用者设置)与控件用来显示的“内部”绑定分开文本。