gpt4 book ai didi

wpf - 如何设置以 TreeView 样式定义的 ContextMenu 的 DataContext

转载 作者:行者123 更新时间:2023-12-03 10:16:14 25 4
gpt4 key购买 nike

我有一个 TreeView,它的 ContextMenu 在 Style 中定义。 MenuItems 具有绑定(bind)到它们的命令,但我无法绑定(bind)这些命令。我意识到这是因为视觉树中不存在 ContextMenu,所以我尝试使用我在其他示例中看到的 PlacementTarget 对象和 Tag 属性,但它仍然无法正常工作。任何想法我做错了什么。

<Grid Name="MyGrid" DataContext="{Binding}">
<TreeView Name="TreeView"
ItemsSource="{Binding TreeViewElements}"
Tag="{Binding DataContext, ElementName=MyGrid}">
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu DataContext="{Binding PlacementTarget.Tag, RelativeSource={x:Static RelativeSource.Self}}">
<MenuItem Header="Do Something"
Command="{Binding DoSomethingCommand}"/>
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</TreeView.ItemContainerStyle>
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding SubElements}">
<StackPanel Orientation="Horizontal">
<TextBlock Margin="2" Text="{Binding HeaderText}" ></TextBlock>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Grid>

更新

下面的答案都是完全有效和正确的,但经过一番思考后,我意识到我在错误地看待这个问题。我看了一下 this article by Josh Smith他解释说,使用 ViewModel 模式意味着您将 TreeView 用于 显示数据 而不是 放数据 .结果,我能够将 TreeView 中的每个项目视为它自己的 View 模型。这意味着我可以从上下文菜单中针对特定 ViewModel 执行任何命令(如果需要,可以使用新 ViewModel 上的父属性导航到父 View 模型)。

最佳答案

ContextMenu 确实有 DataContext。您不需要显式设置它。

在您的情况下,ContextMenu 中的 DataContext 与 TreeViewItem 相同。这意味着它不是 ViewModel,而是项目本身。

假设您有一个 Person 类型的对象列表。那么这个命令应该放在 Person 里面。

public class Person : INotifyPropertyChanged
{
private string name;

public string Name
{
get { return name; }
set { name = value; this.OnPropertyChanged("Name"); }
}

public ICommand DoSomethingCommand
{
get
{
return new RelayCommand(x => MessageBox.Show("Works!"));
}
}

...

然后 XAML 应该如下所示:
        <TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Header="Do Something"
Command="{Binding DoSomethingCommand}"/>
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</TreeView.ItemContainerStyle>

但是,如果您在 ViewModel 中有命令,那么您需要将 ViewModel 的实例提供给 ContextMenu 的 DataContext。

这是一个例子:
class MainWindowViewModel : INotifyPropertyChanged
{
private ObservableCollection<Person> employee;

public MainWindowViewModel()
{
this.Employee = new ObservableCollection<Person>();
this.Employee.Add(new Person { Name = "Test" });
}

public ObservableCollection<Person> Employee
{
get { return this.employee; }
set { this.employee = value; this.OnPropertyChanged("Employee"); }
}

public ICommand DoSomethingCommand
{
get
{
return new RelayCommand(x => MessageBox.Show("Works!"));
}
}

...

然后 XAML 将如下所示:
    <TreeView x:Name="treeView" ItemsSource="{Binding Employee}">
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="Tag" Value="{Binding RelativeSource={RelativeSource AncestorType=TreeView}, Path=DataContext}"></Setter>
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu DataContext="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Do Something"
Command="{Binding DoSomethingCommand}"/>
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</TreeView.ItemContainerStyle>
</TreeView>

或者 XAML 可能如下所示:
    <TreeView x:Name="treeView" ItemsSource="{Binding Employee}">
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu DataContext="{x:Reference treeView}">
<MenuItem Header="Do Something"
Command="{Binding DataContext.DoSomethingCommand}"/>
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</TreeView.ItemContainerStyle>
</TreeView>

关于wpf - 如何设置以 TreeView 样式定义的 ContextMenu 的 DataContext,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20706017/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com