[WPF]UserControl.DataContext 繼承關係
參考:http://www.codeproject.com/Articles/325911/A-Simple-Pattern-for-Creating-Re-useable-UserContr
此範例(及參考網頁)以UserControl為範例,說明當在MainPage(主頁)調用時,UserControl.DataContext 依賴關係。
UserControl.DataContext 會是暴露(public)的,若找不到參考的DataContext依賴關係會向上一直到找到為止(至最上層MainPage的DataContext)。
再補充一種狀況:
情境:若UserControl內的依賴屬性要參考本身的DataContext(ViewModel),而不是繼承父類 。
錯誤代碼如下:
//UserControl.xaml <UserControl x:Class="UserControlExample.FieldUserControl" ...> <StackPanel Orientation="Horizontal" > <!--Control Putting and Do Bind--> </StackPanel> </UserControl>
//UserControlView .xaml.cs
public FieldUserControl(){
InitializeComponent();
this.DataContext =new FieldViewModel();
}
#region Label DP /// <span class="code-SummaryComment"><summary> </span> /// Gets or sets the Label which is displayed next to the field /// <span class="code-SummaryComment"></summary> </span> public String Label { get { return (String)GetValue(LabelProperty); } set { SetValue(LabelProperty, value); } } /// <span class="code-SummaryComment"><summary> </span> /// Identified the Label dependency property /// <span class="code-SummaryComment"></summary> </span> public static readonly DependencyProperty LabelProperty = DependencyProperty.Register("Label", typeof(string), typeof(FieldUserControl), new PropertyMetadata("")); #endregion
調用代碼如下:
<MainPage….>
<Grid> <StackPanel Orientation="Vertical" HorizontalAlignment="Left" Margin="10"> <local:FieldUserControl VerticalAlignment="Top" Label="Height:" Value="{Binding Height}"/> </StackPanel> </Grid>
</MainPage>
上述有說到UserControl.DataContext 是暴露的,當在MainPage內並無設定UserControl.DataContext將
造成UserControl.DataContext被父類覆蓋(繼承父類)。
解法:
//UserControl.xaml <UserControl x:Class="UserControlExample.FieldUserControl" ...> <StackPanel Orientation="Horizontal" x:Name="LayoutRoot"> ... </StackPanel> </UserControl>
//UserControl.xaml.cs
public FieldUserControl()
{ InitializeComponent(); LayoutRoot.DataContext = new FieldViewModel(); }
為什麼LayoutRoot.DataContext = new FieldViewModel();,就不會造成向上繼承。因為它封閉在FieldUserControl內,並不直接暴露於外面,將不會直接受最上層父類影響;然而UserControl .DataContext是暴露在FieldUserControl外層,若調用的View(MainPage)沒給值會自動繼承父類模板的依賴屬性,看一下調用代碼即可發現,並沒賦予FieldUserControl.DataContext值。
此視覺樹,是在說明DataContext 的引響範圍。
1.藍色部分:MainPage將會一直引響到FieldUserControl所暴露的依賴屬性,只要控件在此被調用,並且調用端(MainPage)沒給予UserControl的依賴屬性綁定值,則該UserControl的依賴屬性將自動繼承父類屬性,這說明了 若再UserControl的建構子內寫上this.DataContext =new ViewModel()是無意義的。
2.綠色部分:綠色部分為FieldUserControl封閉的部分,裡面的屬性將不直接受最上端調用者影響,但一樣會繼承FieldUserControl的依賴屬性。但是若在StackPanel內寫上StackPanelName(自訂義).DataContext = new ViewModel() ,將無視FieldUserControl.DataContext影響。
By-藍小伙