我的 DataContext 改变了。如何正确执行绑定
My DataContext changed. How to properly perform Binding
我正在开发 UserControl,其中我有基于自定义 class 的 TreeView,构建方式如下:
-连接模型
---模式模型
-----架构集合
--------表格模型
TreeView 工作得很好。
我在单击 TreeView 中的 TableModel 项目后添加了 ContextMenu。
然后我想创建绑定到我在 SideBar() class 中声明的 Command "SelectFromTab" (这是此 View 的 ModelView )。
我应该如何正确绑定到 SideBar 中的 SelectFromTab 命令 class?
现在 ContextMenu 的 DataContext 设置为 "TableModel"。
我的看法(完整。xaml)
<Page
....
xmlns:local="clr-namespace:ProgDB4.ViewModel"
xmlns:models="clr-namespace:ProgDB4.Model"
xmlns:ProgDB4="clr-namespace:ProgDB4" x:Name="page" x:Class="ProgDB4.ViewModel.SideBar"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
Title="SideBar">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="20"/>
</Grid.RowDefinitions>
<TabControl Grid.Row="0" x:Name="SideBarTabControl" SelectionChanged="SideBarTabControl_SelectionChanged">
<TabItem Header="Map" Content="Mapa"/>
<TabItem Header="History" Content="History"/>
<TabItem Header="Aliases" x:Name="tab_aliases" Width="52">
<Grid>
<TreeView x:Name="AliasTree" ItemsSource="{Binding TVData}">
<TreeView.Resources >
<HierarchicalDataTemplate DataType="{x:Type models:ConnectionModel}" ItemsSource="{Binding schemas}">
<TextBlock Text="{Binding alias}" />
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type models:SchemaModel}" ItemsSource="{Binding schema_collections}">
<TextBlock Text="{Binding SCHEMA_NAME}" />
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type models:SchemaCollection}" ItemsSource="{Binding collection}">
<TextBlock Text="{Binding SCHEMA_COLLECTION_NAME}" />
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type models:TableModel}" >
<TextBlock Text="{Binding TABLE_NAME}" PreviewMouseRightButtonDown="TextBlock_PreviewMouseRightButtonDown" >
<TextBlock.ContextMenu>
<ContextMenu>
<MenuItem Header="SELECT TOP 100" Command ="{Binding SelectFromTab}"/>
<MenuItem Header="SELECT TOP 1000"/>
<MenuItem Header="Display indexes"/>
<MenuItem Header="Display columns"/>
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>
</DataTemplate>
</TreeView.Resources>
</TreeView>
</Grid>
</TabItem>
</TabControl>
<TextBox x:Name="SearchBox" Text="Search..." Height="20" Grid.Row="1" TextChanged="SearchBox_TextChanged" GotFocus="SearchBox_GotFocus" LostFocus="SearchBox_LostFocus"/>
</Grid>
我的边栏class:
public partial class SideBar : Page, INotifyPropertyChanged
{
private List<ConnectionModel> _TVData;
public MainViewModel mainViewModelContext;
public TreeView tmpAliasTree = new TreeView();
public ICommand _SelectFromTab;
public ICommand SelectFromTab
{
get
{
MessageBox.Show("ddd");
return _SelectFromTab;
}
set { if (value != _SelectFromTab) { _SelectFromTab = value; } }
}
public SideBar( MainViewModel mainViewContext )
{
TreeViewBase = new List<ConnectionModel>(ConnectionUtilities.LoadObservableConnections());
mainViewModelContext = mainViewContext ;
InitializeComponent();
this.DataContext = this ;
// this.SelectFromTab = mainViewModelContext.SelectFromTab ;
var loadSideBar = Task.Factory.StartNew(async () => { await LoadSideBar(); });
loadSideBar.Wait();
OnPropertyChanged("TVData");
}
据我所知,问题是将 TableModel 项的 ContextMenu 命令绑定到它的父级 (UserControl) DataContext "SelectFromTab" 命令。如果是,则需要在绑定模式为 FindAncestor 时执行 RelativeSource 绑定。但是这里有一些小问题,TabModel 项的可视树中不存在 ContextMenu。请将下一个示例作为您研究的起点。
XAML
<Style TargetType="SetHereTheTypeOfDataContextMenyTargetControl">
<Setter Property="dataGridCreateColumnAndBindIteFromCodeBehind:Attached.ParentDataContextToTag" Value="True"></Setter>
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu DataContext="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
<MenuItem Header="MenuItem One"
Command="{Binding CmdMenuItemOne}" />
<MenuItem Header="MenuItem Two"
Command="{Binding CmdMenuItemTwo}" />
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
附属性代码
public class Attached
{
public static readonly DependencyProperty SetDataGridDataContextToTagProperty = DependencyProperty.RegisterAttached(
"SetDataGridDataContextToTag", typeof (bool), typeof (Attached), new PropertyMetadata(default(bool), SetParentDataContextToTagPropertyChangedCallback));
public static void SetSetDataGridDataContextToTag(DependencyObject element, bool value)
{
element.SetValue(SetDataGridDataContextToTagProperty, value);
}
public static bool GetSetDataGridDataContextToTag(DependencyObject element)
{
return (bool) element.GetValue(SetDataGridDataContextToTagProperty);
}
private static void SetParentDataContextToTagPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
{
PerformDataContextToTagAssignment(dependencyObject as FrameworkElement, (bool)args.NewValue);
}
private static void PerformDataContextToTagAssignment(FrameworkElement sender, bool isAttaching)
{
var control = sender;
if (control == null) return;
if (isAttaching == false)
{
control.Tag = null;
}
else
{
var dataGrid = control.FindParent<PutHereTheTypeOfVisualParentWhichDataContextYouNeed>();
if (dataGrid == null) return;
control.Tag = dataGrid.DataContext;
}
}
}
帮手代码
public static class VisualTreeHelperExtensions
{
public static T FindParent<T>(this DependencyObject child) where T : DependencyObject
{
while (true)
{
//get parent item
DependencyObject parentObject = VisualTreeHelper.GetParent(child);
//we've reached the end of the tree
if (parentObject == null) return null;
//check if the parent matches the type we're looking for
T parent = parentObject as T;
if (parent != null)
return parent;
child = parentObject;
}
}
}
如果您需要代码方面的帮助或需要帮助,请告诉我。
此致。
ContextMenu
与您的 UserControl
不同 DataContext
。您可以手动设置。
private void ContextMenu_Loaded(object sender, RoutedEventArgs e)
{
(sender as FrameworkElement).DataContext = this;
}
你的命令会正常工作。
我正在开发 UserControl,其中我有基于自定义 class 的 TreeView,构建方式如下:
-连接模型
---模式模型
-----架构集合
--------表格模型
TreeView 工作得很好。
我在单击 TreeView 中的 TableModel 项目后添加了 ContextMenu。 然后我想创建绑定到我在 SideBar() class 中声明的 Command "SelectFromTab" (这是此 View 的 ModelView )。
我应该如何正确绑定到 SideBar 中的 SelectFromTab 命令 class? 现在 ContextMenu 的 DataContext 设置为 "TableModel"。
我的看法(完整。xaml)
<Page
....
xmlns:local="clr-namespace:ProgDB4.ViewModel"
xmlns:models="clr-namespace:ProgDB4.Model"
xmlns:ProgDB4="clr-namespace:ProgDB4" x:Name="page" x:Class="ProgDB4.ViewModel.SideBar"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
Title="SideBar">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="20"/>
</Grid.RowDefinitions>
<TabControl Grid.Row="0" x:Name="SideBarTabControl" SelectionChanged="SideBarTabControl_SelectionChanged">
<TabItem Header="Map" Content="Mapa"/>
<TabItem Header="History" Content="History"/>
<TabItem Header="Aliases" x:Name="tab_aliases" Width="52">
<Grid>
<TreeView x:Name="AliasTree" ItemsSource="{Binding TVData}">
<TreeView.Resources >
<HierarchicalDataTemplate DataType="{x:Type models:ConnectionModel}" ItemsSource="{Binding schemas}">
<TextBlock Text="{Binding alias}" />
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type models:SchemaModel}" ItemsSource="{Binding schema_collections}">
<TextBlock Text="{Binding SCHEMA_NAME}" />
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type models:SchemaCollection}" ItemsSource="{Binding collection}">
<TextBlock Text="{Binding SCHEMA_COLLECTION_NAME}" />
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type models:TableModel}" >
<TextBlock Text="{Binding TABLE_NAME}" PreviewMouseRightButtonDown="TextBlock_PreviewMouseRightButtonDown" >
<TextBlock.ContextMenu>
<ContextMenu>
<MenuItem Header="SELECT TOP 100" Command ="{Binding SelectFromTab}"/>
<MenuItem Header="SELECT TOP 1000"/>
<MenuItem Header="Display indexes"/>
<MenuItem Header="Display columns"/>
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>
</DataTemplate>
</TreeView.Resources>
</TreeView>
</Grid>
</TabItem>
</TabControl>
<TextBox x:Name="SearchBox" Text="Search..." Height="20" Grid.Row="1" TextChanged="SearchBox_TextChanged" GotFocus="SearchBox_GotFocus" LostFocus="SearchBox_LostFocus"/>
</Grid>
我的边栏class:
public partial class SideBar : Page, INotifyPropertyChanged
{
private List<ConnectionModel> _TVData;
public MainViewModel mainViewModelContext;
public TreeView tmpAliasTree = new TreeView();
public ICommand _SelectFromTab;
public ICommand SelectFromTab
{
get
{
MessageBox.Show("ddd");
return _SelectFromTab;
}
set { if (value != _SelectFromTab) { _SelectFromTab = value; } }
}
public SideBar( MainViewModel mainViewContext )
{
TreeViewBase = new List<ConnectionModel>(ConnectionUtilities.LoadObservableConnections());
mainViewModelContext = mainViewContext ;
InitializeComponent();
this.DataContext = this ;
// this.SelectFromTab = mainViewModelContext.SelectFromTab ;
var loadSideBar = Task.Factory.StartNew(async () => { await LoadSideBar(); });
loadSideBar.Wait();
OnPropertyChanged("TVData");
}
据我所知,问题是将 TableModel 项的 ContextMenu 命令绑定到它的父级 (UserControl) DataContext "SelectFromTab" 命令。如果是,则需要在绑定模式为 FindAncestor 时执行 RelativeSource 绑定。但是这里有一些小问题,TabModel 项的可视树中不存在 ContextMenu。请将下一个示例作为您研究的起点。
XAML
<Style TargetType="SetHereTheTypeOfDataContextMenyTargetControl">
<Setter Property="dataGridCreateColumnAndBindIteFromCodeBehind:Attached.ParentDataContextToTag" Value="True"></Setter>
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu DataContext="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
<MenuItem Header="MenuItem One"
Command="{Binding CmdMenuItemOne}" />
<MenuItem Header="MenuItem Two"
Command="{Binding CmdMenuItemTwo}" />
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
附属性代码
public class Attached
{
public static readonly DependencyProperty SetDataGridDataContextToTagProperty = DependencyProperty.RegisterAttached(
"SetDataGridDataContextToTag", typeof (bool), typeof (Attached), new PropertyMetadata(default(bool), SetParentDataContextToTagPropertyChangedCallback));
public static void SetSetDataGridDataContextToTag(DependencyObject element, bool value)
{
element.SetValue(SetDataGridDataContextToTagProperty, value);
}
public static bool GetSetDataGridDataContextToTag(DependencyObject element)
{
return (bool) element.GetValue(SetDataGridDataContextToTagProperty);
}
private static void SetParentDataContextToTagPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
{
PerformDataContextToTagAssignment(dependencyObject as FrameworkElement, (bool)args.NewValue);
}
private static void PerformDataContextToTagAssignment(FrameworkElement sender, bool isAttaching)
{
var control = sender;
if (control == null) return;
if (isAttaching == false)
{
control.Tag = null;
}
else
{
var dataGrid = control.FindParent<PutHereTheTypeOfVisualParentWhichDataContextYouNeed>();
if (dataGrid == null) return;
control.Tag = dataGrid.DataContext;
}
}
}
帮手代码
public static class VisualTreeHelperExtensions
{
public static T FindParent<T>(this DependencyObject child) where T : DependencyObject
{
while (true)
{
//get parent item
DependencyObject parentObject = VisualTreeHelper.GetParent(child);
//we've reached the end of the tree
if (parentObject == null) return null;
//check if the parent matches the type we're looking for
T parent = parentObject as T;
if (parent != null)
return parent;
child = parentObject;
}
}
}
如果您需要代码方面的帮助或需要帮助,请告诉我。
此致。
ContextMenu
与您的 UserControl
不同 DataContext
。您可以手动设置。
private void ContextMenu_Loaded(object sender, RoutedEventArgs e)
{
(sender as FrameworkElement).DataContext = this;
}
你的命令会正常工作。