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.....
我明显地做了上面的事情。
谢谢!
答案 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;
}