通过DataContext从ViewModel获取值而不进行绑定?

时间:2012-02-24 19:50:55

标签: wpf mvvm user-controls wpf-controls

WPF新手。我正在创建需要对ViewModel状态的读访问权来执行其操作的UserControl。我目前使用以下技术:

public partial class ControlBar : UserControl
{

    private static readonly DependencyProperty URLProperty =
        DependencyProperty.Register("URL", typeof(string), typeof(ControlBar),
        new UIPropertyMetadata(null));

    public ControlBar()
    {
        InitializeComponent();

        SetBinding(URLProperty, "CurrentPage.URL");

        Pin.Click += Pin_Click;       
    }

    private void Pin_Click(object sender, RoutedEventArgs e)
    {
        var URL = (string)GetValue(URLProperty);

    }
}

这是正确的方法吗?为我需要访问的每个变量设置长期绑定是不是太过分了?或者你能做点什么:

GetValue(new Path("CurrentPage.URL..... 

我明显地做了上面的事情。

谢谢!

1 个答案:

答案 0 :(得分:4)

通常,数据绑定是可行的方法。但是,有时当您创建具有视图特定关注点的控件时,数据绑定将不合适。

在这些情况下,您将希望能够与DependencyProperty进行交互以设置它并知道它何时发生变化。我一直在遵循我从MSDN杂志上的Charles Petzold文章中选择的模式。

我对另一个问题的回答显示了为UserControl创建DependencyProperty的模式Stack Overflow: Dependency Property In WPF/SilverLight

同样,对视图模型的数据绑定可能会解决您的问题,但根据具体情况,DependencyProperty可能会有用。

回复评论时更新:

在许多情况下,您可以在不使用DependencyProperty的情况下将数据绑定到UserControl中。例如,如果您有一个显示名称的TextBlock,您将把TextBlock放在UserControl的XAML中

<TextBlock Text="{Binding Path=NameString}" />

在DataContext中存在的视图模型中,您将拥有一个属性NameString,如果TextBlock在NameString属性更改时更新显示,则视图模型应实现INotifyPropertyChanged,并且该属性应使用名称触发PropertyChanged事件与该事件一起发送的财产。

protected string _NameString;
public string NameString
{
    get { return _NameString; }
    set { _NameString = value: Notify("NameString"); }
}

Notify是一种检查PropertyChanged事件为null的方法,如果不为null则发送该事件。

如果您想要使用UserControl的任何地方都有一个带有Name属性的视图模型,那么这很有效。最棒的是,UserControl可以接收托管所在位置的DataContext并绑定到外部视图模型。

当您想要将相同的UserControl绑定到不同的属性时,您可能想要使用DependencyProperty。在这种情况下,您可以使用DependencyProperty创建UserControl并将其绑定到不同的属性

<my:SampleControl NameString="{Binding Path=GivenName}" />
<my:SampleControl NameString="{Binding Path=FamilyName}" />

然后有一个内部视图模型,当绑定属性发生更改时,DependencyProperty更改处理程序会更新。

更新:没有DependencyProperty或绑定

您始终可以向UserControl添加普通的C#属性,并以这种方式传递数据。

public MyClass Data { get; set; }

然后在UserControl的代码隐藏中,您只需使用属性:

if (this.Data != null)
{
    this.textBox1.Text = Data.NameString;
}

回复评论时更新:

在代码中访问视图模型的另一种方法是将DataContext强制转换为视图模型类型:

MyClass data = this.DataContext as MyClass;
if (data != null)
{
    // do something
    this.textBox1.Text = data.NameString;
}