2013-04-08 127 views
1

我一直在努力使这一障碍在WPF中,我想我已经找到了解决办法,虽然难看。绑定依赖项属性为当前DataContext属性

的情况如下:

  • 我有一个自定义依赖属性的自定义用户控件。
  • 用户控件可以嵌套在我的其他用户控件内。
  • 我的每个用户控件都有一个由定位器指定的数据上下文(我遵循MVVM模式)
  • 我想将自定义依赖项属性绑定到父视图模型中的值。

代码...

父视图

<UserControl DataContext="{Binding Source={StaticResource Locator}, Path=ParentControlLocator}"> 

    <my:Child Demo="{Binding Path=DataContext.DemoTextAlpha, RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl, AncestorLevel=1}}" /> 

</UserControl> 

父类视图模型

public class ParentClassViewModel : BaseViewModel 
{ 
    private string _demoTextAlpha = "Some Alpha text"; 

    public string DemoTextAlpha 
    { 
     get 
     { 
      return this._demoTextAlpha; 
     } 
     set 
     { 
      this._demoTextAlpha = value; 
      this.NotifyPropertyChange("DemoTextAlpha"); 
     } 
    } 
} 

子视图

<UserControl DataContext="{Binding Source={StaticResource Locator}, Path=ChildControlLocator}"> 

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

</UserControl> 

儿童查看代码背后

public partial class Child : UserControl 
{ 
    public Child() 
    { 
     InitializeComponent(); 
    } 

    public static readonly DependencyProperty DemoProperty = 
      DependencyProperty.Register("Demo", 
             typeof(string), 
             typeof(Child), 
             new FrameworkPropertyMetadata() 
             { 
              PropertyChangedCallback = OnDemoChanged, 
              BindsTwoWayByDefault = true 
             }); 

    public string Demo 
    { 
     get { return this.GetValue(DemoProperty).ToString(); } 
     set { this.SetValue(DemoProperty, value); } 
    } 

    private static void OnDemoChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     var control = (Child)d; 
     var viewModel = (ChildViewModel)control.DataContext; 

     viewModel.SomeProperty = (string)e.NewValue; 
    } 
} 

子视图模式

public class ChildViewModel : BaseViewModel 
{ 
    private string _someProperty; 

    public string SomeProperty 
    { 
     get 
     { 
      return _someProperty; 
     } 
     set 
     { 
      _someProperty = value; 
      this.NotifyPropertyChange("SomeProperty"); 
     } 
    } 
} 

好了,所以这WORKS。我试图达到的是更好/更优雅的代码,特别是关于这个声明。

<my:Child Demo="{Binding Path=DataContext.DemoTextAlpha, RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl, AncestorLevel=1}}" /> 

即使我能忍受,尽量优雅的推移,但有一点是困扰我现在的问题是,当我键入

Path=DataContext.DemoTextAlpha 

当我尝试向下钻取智能感知下降在DataContext中。所以我必须格外小心地输入正确的东西。

那么 - 有什么不同的方式,使在DataContext的属性出现在智能感知,或者是有另一种方式来实现这一目标,我现在在做同样的事情?

谢谢。

EDIT到澄清

当我把这样的事情,而不是指定的相对源如在上述实施例...

<my:Child Demo="{Binding DemoTextAlpha}"/> 

我收到错误...

System.Windows.Data Error: 40 : BindingExpression path error: 'DemoTextAlpha' property not found on 'object' ''ChildViewModel' (HashCode=34126977)'. BindingExpression:Path=DemoTextAlpha; DataItem='ChildViewModel' (HashCode=34126977); target element is 'Child' (Name=''); target property is 'Demo' (type 'String') 

回答

5

DataContext的(与很多其它性能如FontSize的沿)为沿视件树"Inherited"。因此这样的:

<UserControl DataContext="{Binding Source={StaticResource Locator}, Path=ParentControlLocator}"> 
    <my:Child Demo="{Binding Path=DataContext.DemoTextAlpha, RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl, AncestorLevel=1}}" /> 
</UserControl> 

是完全一样的:

<UserControl DataContext="{Binding Source={StaticResource Locator}, Path=ParentControlLocator}"> 
    <my:Child Demo="{Binding DemoTextAlpha}"/> 
</UserControl> 

至于智能感知的支持,我不知道你使用的是什么版本的VS,但我使用VS 2010专业版与ReSharper的6.1,它增加了智能感知实现M如果指定d:DataContext值:

<UserControl x:Class="...etc." 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:local="clr-namespace:TheViewModelNamespace" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      mc:Ignorable="d" d:DataContext="{d:DesignInstance local:ViewModel}"> 

编辑:

确定..让我们analize你在这里做什么:

- 绑定用户控件到ParentVM:

ParentVM -> UserControl 

- 使用的RelativeSource要从ParentVM中获取一些属性并将其放置到您在子控件中创建的自定义DP中

ParentVM -> UserControl -> Child Control 

- 在自定义DP的OnPropertyChanged,同样的值设置为ChildVM

ParentVM -> UserControl -> Child Control -> ChildVM 

你有没有意识到你正在使用的视图(用户控制,子控件)作为中间分享2视图模型之间的一些属性?你为什么不只是

ParentVM -> ChildVM 

哪一个会更容易,更干净,真的MVVM?

要么从ParentVM直接引用ChildVM,要么使用类似于Messenger模式的内容在它们之间进行间接通信。

+1

请检查我的编辑到OP看到我的澄清...我试图把它放在评论中,但我无法正确格式化。 – imdandman 2013-04-08 16:44:44

+0

@imdandman看到我的编辑。 – 2013-04-08 17:00:56

+0

Drat!我忽略的另一件事。 你所说的是我一直在做的事情。我在构造函数中引用了其他虚拟机,当我需要填充数据时,我只是这样做了。 但是,当我需要将2x的ChildControl放置在同一父级中时,我遇到了此问题。那有意义吗? – imdandman 2013-04-08 17:05:08

1

的DataContext继承:

<UserControl DataContext="{Binding Source={StaticResource Locator}, Path=ParentControlLocator}"> 

    <my:Child Demo="{Binding DemoTextAlpha}" /> 

</UserControl> 

如果伊娜不同的情况下,你的子控件都指定了不同的DataContext,你仍然需要绑定到父控件的DataContext的属性,使用ElementName可能更好:

<UserControl x:Name="Parent" DataContext="{Binding Source={StaticResource Locator}, Path=ParentControlLocator}"> 

    <my:Child Demo="{Binding Path=DataContext.DemoTextAlpha, ElementName=Parent}" /> 

</UserControl>