我对WPF ContextMenu
中的DataGridColumn
提出了一个棘手的问题。我不知道是否有人已经面对这个问题,但如果有人能帮助我,我将非常感激!
让我们从我的课程开始
public class Person
{
public string Type { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public int Age { get; set; }
}
public class Menu
{
public string Name { get; set; }
public int Code { get; set; }
public ObservableCollection<Menu> listMenu { get; set; }
}
现在我的ViewModel
public class MyViewModel : INotifyPropertyChanged
{
private ObservableCollection<Person> DataPersons = new ObservableCollection<Person>();
private ObservableCollection<Menu> DataMenu = new ObservableCollection<Menu>();
public ObservableCollection<Person> listDataPersons { get; set; }
public ObservableCollection<Menu> listDataMenu { get; set; }
public MyViewModel()
{
//initialization
InitData();
}
private void InitData()
{
listDataPersons = new ObservableCollection<Person>();
listDataMenu = new ObservableCollection<Menu>();
DataPersons.Add(new Person() { Type = "Friend", Name = "Doe", Surname = "John", Age = 42});
DataPersons.Add(new Person() { Type = "Friend", Name = "Smith", Surname = "Jack", Age = 42});
DataMenu.Add(new Menu() { Name = "Principal", Code = 1});
DataMenu.Add(new Menu() { Name = "Secondary", Code = 2});
DataMenu.Add(new Menu() { Name = "Associated", Code = 3});
DataMenu[2].listMenu = new ObservableCollection<Menu>();
DataMenu[2].listMenu.Add(new Menu() { Name = "Associated 1", Code = 31 });
listDataPersons = DataPersons;
listDataMenu = DataMenu;
}}
以下是我的View及其背后的代码
<DataGrid ItemsSource="{Binding listDataPersons}" AutoGenerateColumns="False">
<DataGrid.ContextMenu>
<ContextMenu ItemsSource="{Binding listDataMenu}"/>
</DataGrid.ContextMenu>
<DataGrid.Columns>
<DataGridTemplateColumn IsReadOnly="True" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" Width="80" >
<TextBlock.ContextMenu>
<ContextMenu ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGridCell}}, Path=DataContext.listDataMenu}"/>
</TextBlock.ContextMenu>
</TextBlock>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
背后的代码
public partial class MyView : UserControl
{
public MyView()
{
InitializeComponent();
this.DataContext = new MyViewModel();
}
}
在此示例中,我想要的是在ContextMenu
中拥有动态DataGridColumn
。首先,我在整个ContextMenu
中添加了DataGrid
,它运行正常。但在我的情况下,我只需要在单元格中右键单击ContextMenu
而不是整个DataGrid
。因此,我尝试使用DataGridColumn
编辑DataTemplate
的{{1}} TextBox
。不幸的是,当我右键点击ContextMenu
时TextBox
ContextMenu
ItemsSource
似乎是空的。但是,当我在TextBox
的{{1}}外右键单击时,DataGrid
的{{1}}被正确绑定。
我认为这可能是DataGrid
的问题,因为ContextMenu
和DataContext
没有相同的可视树,所以我在{{1}添加了ContextMenu
} DataGrid
绑定但没有结果!!!
有什么想法吗?
答案 0 :(得分:1)
首先感谢Rick花时间指导我解决这个问题。
我在msdn论坛上发布了这个问题,我得到了解决它的答案
<TextBlock Text="{Binding Name}" Width="80" Tag="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type DataGrid}}, Path=DataContext}">
<TextBlock.ContextMenu>
<ContextMenu ItemsSource="{Binding RelativeSource={RelativeSource Self}, Path=PlacementTarget.Tag.listDataMenu}" ItemContainerStyle="{StaticResource ContextMenuItemStyle}"/>
</TextBlock.ContextMenu>
要做的是通过TextBox的标签将UserControl的DataContext传递给TextMenu
对于那些想要使用我的代码使其正常工作的人,您需要将UserControlRessoucre定义为:
<UserControl.Resources>
<HierarchicalDataTemplate DataType="{x:Type cmd:Menu}" ItemsSource="{Binding listMenu}">
<TextBlock Text="{Binding Path=Name}"/>
</HierarchicalDataTemplate>
<Style x:Key="ContextMenuItemStyle">
<Setter Property="MenuItem.ItemsSource" Value="{Binding Path=listMenu}"/>
</Style>
</UserControl.Resources>
这是原始答案的msdn论坛链接:-->here<--
非常感谢Sheldon Xiao的回答
答案 1 :(得分:0)
你走在正确的轨道上。您需要使用RelativeSource
,但需要使用Self
,然后使用PlacementTarget
将可视树交换到TextBox
,您可以从DataContext
获取其DataGridCell
应该是从<ContextMenu ItemsSource="{Binding RelativeSource={RelativeSource Self}, Path=PlacementTarget.DataContext.listDataMenu}"/>
继承而来,最终能够到达您的菜单属性。
我的意思是未经测试的例子:
{{1}}
答案 2 :(得分:0)
即使我在Datagrid中的每一行都需要相同的contextMenu,我尝试了你的建议并且无法使其工作:(可能是我忘记了某事
听到我们这样修改我的课程:
public class Person
{
public string Type { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public int Age { get; set; }
public Column Column { get; set; }
}
public class Menu
{
public string Name { get; set; }
public int Code { get; set; }
public ObservableCollection<Menu> listMenu { get; set; }
}
public class Column
{
public ObservableCollection<Menu> listDatatMenu { get; set; }
}
然后我在我的ViewModel中更改InitData函数,如:
private void InitData()
{
listDataPersons = new List<Person>();
listDataMenu = new ObservableCollection<Menu>();
DataPersons.Add(new Person() { Type = "Friend", Name = "Doe", Surname = "John", Age = 42});
DataPersons.Add(new Person() { Type = "Friend", Name = "Smith", Surname = "Jack", Age = 42});
DataMenu.Add(new Menu() { Name = "Principal", Code = 1});
DataMenu.Add(new Menu() { Name = "Secondary", Code = 2});
DataMenu.Add(new Menu() { Name = "Associated", Code = 3});
DataMenu[2].listMenu = new ObservableCollection<Menu>();
DataMenu[2].listMenu.Add(new Menu() { Name = "Associated 1", Code = 31 });
DataPersons[0].Column = new Column();
DataPersons[0].Column.listDatatMenu = DataMenu;
DataPersons[1].Column = new Column();
DataPersons[1].Column.listDatatMenu = DataMenu;
listDataPersons = DataPersons;
listDataMenu = DataMenu;
}
最后是我视图中的ContextMenu
<ContextMenu ItemsSource="{Binding RelativeSource={RelativeSource Self}, Path=PlacementTarget.DataContext.Column.listDataMenu}"/>
如果我犯了一个菜鸟错误但确实有效,请感到抱歉
答案 3 :(得分:0)
上下文菜单不能尽可能轻松地工作,因为默认情况下,它们与其他所有内容都在不同的可视树中,因此无法找到DataContext
。
关键的见解是创建一个定义上下文菜单的
<Style>
, 然后将该样式附加到目标元素,该元素将连接上下文 菜单。 这会将上下文菜单转换为与您想要的默认DataContext
对齐的可视树。
首先,创建样式:
<UserControl.Resources>
<ResourceDictionary>
<!-- For the context menu to work, we must shift it into a style, which means that the context menu is now in a
visual tree that is more closely related to the current data context. All we have to do then is set the style,
which hooks up the context menu. -->
<Style x:Key="ContextMenuStyle" TargetType="{x:Type StackPanel}">
<Setter Property="ContextMenu" Value="{DynamicResource TreeViewContextMenu}"/>
</Style>
<ContextMenu x:Key="TreeViewContextMenu">
<MenuItem Header="Test" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.CmdDisplayDetailsGraph}"/>
</ContextMenu>
然后,将上下文菜单挂钩到任何您想要的位置,而不会遇到由不同可视树引起的问题。
示例1:
<HierarchicalDataTemplate DataType="{x:Type snapshot:Details}" ItemsSource="{Binding DetailsList}">
<StackPanel Orientation="Vertical" Style="{StaticResource ContextMenuStyle}">
<ContentPresenter Content="{Binding}" ContentTemplate="{Binding View.DefaultDataRowTemplate}" />
</StackPanel>
示例2:
<DataTemplate DataType="{x:Type snapshot:InstrumentDetails}">
<StackPanel Orientation="Vertical" Style="{StaticResource ContextMenuStyle}">
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Center">