我的 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;
    }

你的命令会正常工作。