2013-04-08 130 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>