2010-08-07 108 views
0

我想正確完成以下操作。我有一個UserControl(ProgramView)。它有一個視圖模型(ProgramViewViewModel)。 ProgramView作爲Window(ProgramWindow)中的子控件使用。 ProgramWindow具有一個公共屬性ProgramId,因此窗口的使用者可以指定想要顯示的程序(數據實體)。 ProgramView有一個屬性ProgramId,因爲它的主要工作是顯示這些數據。 ProgramWindow僅僅是這個用戶控件的包裝窗口。WPF:正確配置窗口與子UserControl(MVVM)

ProgramViewViewModel也有一個屬性ProgramId。對此屬性的更改驅動了視圖模型的操作,該模型使用ProgramView可以綁定到的其他屬性顯示在視圖模型之外。

我想隱藏從ProgramView和ProgramWindow的消費者的視圖模型的操作。

該ProgramId應該通過所有這些層綁定。對ProgramWindow.ProgramId的更改應傳遞給ProgramView.ProgramId,然後傳遞給ProgramViewViewModel.ProgramId。我無法弄清楚如何正確實現這一點。

我目前的做法是將所有三個類中的ProgramId作爲DP表示。在窗口內,我會想象ProgramView被如此實例化:

<local:ProgramView ProgramId="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:ProgramWindow}}, Path=ProgramId}" /> 

這似乎實際上工作。在ProgramView中,我確實獲取了該屬性的更改事件,並且它們似乎具有正確的值。 FindAncestor似乎正常運行。

那麼應該如何同步ProgramViewViewModel.ProgramId屬性?我看到兩種方式。一種方法是在ProgramViewViewModel實例本身上設置Binding,並使用FindAncestor,並在ProgramViewViewModel上找到ProgramId。這有兩個缺點。它需要ProgramViewViewModel將ProgramId作爲依賴項屬性。我寧願避免這種情況,但它可能是可以接受的。無論哪種方式,我都無法在XAML中完成它。

<local:View.DataContext> 
    <local:ProgramViewViewModel 
     ProgramId="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:ProgramView}}, Path=ProgramId}" /> 
</local:View.DataContext> 

這是行不通的。看起來,我不能在實例的實例化中引入綁定表達式。 FindAncestor報告它無法找到ProgramView。我的理論是這個實例在邏輯樹之外,因此不能遍歷它的父節點。

第二個選項更有意義,它將ProgramView.ProgramId屬性綁定到「ProgramId」(在DataContext中)。我無法做到這一點,因爲我無法弄清楚如何在代碼隱藏中定義的屬性上指定綁定表達式。在XAML中是必需的,但ProgramId的類型實際上是存在的。我無法弄清楚如何指定這個屬性。

如果我手動(在ProgramView的代碼後面)創建一個Binding實例並調用SetBinding(ProgramIdProperty,binding),該值不再流入視圖本身。我相信這是因爲我剛剛替換了ProgramView.ProgramId上的綁定,該程序以前由ProgramWindow設置。每個屬性綁定一個?

我剩下的想法是在ProgramView中提供兩個ProgramId屬性。一個綁定到DataContext,另一個綁定到消費者(ProgramWindow),然後編寫同步這兩個的OnValueChanged處理程序。這感覺像一個黑客。另一種是在ProgramView的代碼隱藏內手動監視ProgramView.ProgramId和ProgramView.DataContext的變化,並自己傳播該值。這些想法都不理想。

我正在尋找其他建議。

+0

使用第二ProgramIdProxy性質的作品。我只是不喜歡它。 – wasabi 2010-08-07 18:33:17

回答

0

你的描述似乎詳細,但我無法理解爲什麼你需要實現這樣的設計。我不禁想到幹。

如果您需要在兩個這樣的相關視圖模型中公開依賴屬性,我建議您爲子視圖模型(用於用戶控件視圖)設置第一個屬性(用於程序窗口視圖)。喜歡的東西:

public class MainViewModel : ViewModelBase 
{ 
    public ProgramViewModel ChildViewModel { get; private set; } 

} 

public class ProgramViewModel : ViewModelBase 
{ 
    private int _ProgramId; 

    public int ProgramId 
    { 
     get { return _ProgramId; } 
     set 
     { 
     if (value != _ProgramId) 
     { 
      // set and raise propery changed notification 
     } 
     } 
    } 
} 

的的MainView可以得到使用ChildViewModel.ProgramId(設置爲MainViewModel數據上下文)的財產。 ProgramView通過ProgramId訪問它(將數據上下文設置爲MainViewModel.ChildViewModel)。