Caliburn.Micro: 如何将函数绑定到 DataGrid 的 RowDetailsTemplate 中的上下文菜单项?
Caliburn.Micro: How to bind a function to a context menu item in the RowDetailsTemplate of a DataGrid?
我有一个项目数据网格,其中包含用于行详细信息的子项目数据网格。主 "Items" 数据网格有一个上下文菜单,具有添加或删除项目的功能,这工作正常。还有一个用于行详细信息数据网格 "SubItems" 的上下文菜单,具有我无法正确绑定的类似功能。如果执行我得到以下异常 "System.Exception: 'No target found for method AddSubItem.'"
我拼命尝试了其他帖子中建议的许多其他解决方案,但到目前为止没有任何效果。我很欣赏任何见解。下面是我的测试代码。
ShellViewModel:
using System;
using Caliburn.Micro;
using ContextMenuTest.Models;
namespace ContextMenuTest.ViewModels
{
public class ShellViewModel : Screen
{
public static Random rnd = new Random();
private BindableCollection<ItemModel> items = new BindableCollection<ItemModel>();
public BindableCollection<ItemModel> Items
{
get { return items; }
set
{
items = value;
NotifyOfPropertyChange(() => Items);
}
}
private ItemModel selectedItem = new ItemModel(rnd);
public ItemModel SelectedItem
{
get { return selectedItem; }
set
{
selectedItem = value;
NotifyOfPropertyChange(() => SelectedItem);
}
}
private SubItemModel selectedSubItem = new SubItemModel(rnd);
public SubItemModel SelectedSubItem
{
get { return selectedSubItem; }
set
{
selectedSubItem = value;
NotifyOfPropertyChange(() => SelectedSubItem);
}
}
public ShellViewModel()
{
for(int i = 0; i < 10; i++)
{
Items.Add(new ItemModel(rnd));
}
}
public void AddItem()
{
Items.Add(new ItemModel(rnd));
}
public void RemoveItem()
{
Items.Remove(SelectedItem);
}
public void AddSubItem(object e)
{
var _item = e as ItemModel;
_item.SubItems.Add(new SubItemModel(rnd));
}
public void RemoveSubItem(object e)
{
var _item = e as ItemModel;
_item.SubItems.Remove(SelectedSubItem);
}
}
}
外壳视图:
<Window x:Class="ContextMenuTest.Views.ShellView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ContextMenuTest.Views"
xmlns:cal="http://www.caliburnproject.org"
mc:Ignorable="d"
Title="ShellView" Height="450" Width="800"
>
<Grid Grid.Row="1">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<DataGrid x:Name="Items" Grid.Row="0" AutoGenerateColumns="False" CanUserResizeColumns="True" CanUserAddRows="false"
VerticalAlignment="Stretch" VerticalScrollBarVisibility="Auto" MinHeight="100" SelectedItem="{Binding SelectedItem}">
<DataGrid.ContextMenu>
<ContextMenu cal:Action.TargetWithoutContext="{Binding Path=PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Add Item" cal:Message.Attach="AddItem()"/>
<MenuItem Header="Remove Item" cal:Message.Attach="RemoveItem()"/>
</ContextMenu>
</DataGrid.ContextMenu>
<DataGrid.Columns >
<DataGridTextColumn Header="ID" Binding="{Binding Path=ID, UpdateSourceTrigger=PropertyChanged}" Width="*" IsReadOnly="True"/>
<DataGridTextColumn Header="Name" Binding="{Binding Path=Name, UpdateSourceTrigger=PropertyChanged}" Width="*"/>
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<DataGrid ItemsSource="{Binding Path=SubItems}" AutoGenerateColumns="False" CanUserResizeColumns="True" CanUserAddRows="false"
VerticalAlignment="Stretch" VerticalScrollBarVisibility="Auto" MinHeight="100"
SelectedItem="{Binding Path=SelectedSubItem, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Grid}}">
<DataGrid.ContextMenu>
<ContextMenu cal:Action.TargetWithoutContext="{Binding Path=PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Add Sub Item" cal:Message.Attach="AddSubItem($dataContext)"/>
<MenuItem Header="Remove Sub Item" cal:Message.Attach="RemoveSubItem($dataContext)"/>
</ContextMenu>
</DataGrid.ContextMenu>
<DataGrid.Columns>
<DataGridTextColumn Header="ID" Binding="{Binding Path=ID}" Width="auto" IsReadOnly="True"/>
<DataGridTextColumn Header="Name" Binding="{Binding Path=Name, UpdateSourceTrigger=PropertyChanged}" Width="auto"/>
<DataGridTextColumn Header="Value" Binding="{Binding Path=Value, UpdateSourceTrigger=PropertyChanged}" Width="auto"/>
</DataGrid.Columns>
</DataGrid>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
</Grid>
</Window>
物品型号:
using Caliburn.Micro;
using System;
namespace ContextMenuTest.Models
{
public class ItemModel
{
public Guid ID { get; set; }
public string Name { get; set; }
public BindableCollection<SubItemModel> SubItems { get; set; } = new BindableCollection<SubItemModel>();
public ItemModel(Random rnd)
{
ID = Guid.NewGuid();
Name = "Item " + ID.ToString().Substring(3, 5);
for (int i = 0; i < 5; i++)
{
SubItems.Add(new SubItemModel(rnd));
}
}
}
}
子项目模型:
using System;
namespace ContextMenuTest.Models
{
public class SubItemModel
{
public Guid ID { get; set; }
public string Name { get; set; }
public int Value { get; set; }
public SubItemModel(Random rnd)
{
ID = Guid.NewGuid();
Name = "SubItem " + ID.ToString().Substring(3,5);
Value = rnd.Next();
}
}
}
尝试使用 TagHelper。它适用于您的 requirement.sample 代码如下。
<Grid Background="White" HorizontalAlignment="Stretch" Height="200" Name="GridLayout">
<ListBox x:Name="ListBoxItems">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Tag="{Binding DataContext, ElementName=GridLayout}">
<Grid.ContextMenu>
<ContextMenu Name="cm" cal:Action.TargetWithoutContext="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Open"
cal:Message.Attach="Open($dataContext)">
</MenuItem>
</ContextMenu>
</Grid.ContextMenu>
<TextBlock VerticalAlignment="Center">
.. text..
</TextBlock>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
我有一个项目数据网格,其中包含用于行详细信息的子项目数据网格。主 "Items" 数据网格有一个上下文菜单,具有添加或删除项目的功能,这工作正常。还有一个用于行详细信息数据网格 "SubItems" 的上下文菜单,具有我无法正确绑定的类似功能。如果执行我得到以下异常 "System.Exception: 'No target found for method AddSubItem.'"
我拼命尝试了其他帖子中建议的许多其他解决方案,但到目前为止没有任何效果。我很欣赏任何见解。下面是我的测试代码。
ShellViewModel:
using System;
using Caliburn.Micro;
using ContextMenuTest.Models;
namespace ContextMenuTest.ViewModels
{
public class ShellViewModel : Screen
{
public static Random rnd = new Random();
private BindableCollection<ItemModel> items = new BindableCollection<ItemModel>();
public BindableCollection<ItemModel> Items
{
get { return items; }
set
{
items = value;
NotifyOfPropertyChange(() => Items);
}
}
private ItemModel selectedItem = new ItemModel(rnd);
public ItemModel SelectedItem
{
get { return selectedItem; }
set
{
selectedItem = value;
NotifyOfPropertyChange(() => SelectedItem);
}
}
private SubItemModel selectedSubItem = new SubItemModel(rnd);
public SubItemModel SelectedSubItem
{
get { return selectedSubItem; }
set
{
selectedSubItem = value;
NotifyOfPropertyChange(() => SelectedSubItem);
}
}
public ShellViewModel()
{
for(int i = 0; i < 10; i++)
{
Items.Add(new ItemModel(rnd));
}
}
public void AddItem()
{
Items.Add(new ItemModel(rnd));
}
public void RemoveItem()
{
Items.Remove(SelectedItem);
}
public void AddSubItem(object e)
{
var _item = e as ItemModel;
_item.SubItems.Add(new SubItemModel(rnd));
}
public void RemoveSubItem(object e)
{
var _item = e as ItemModel;
_item.SubItems.Remove(SelectedSubItem);
}
}
}
外壳视图:
<Window x:Class="ContextMenuTest.Views.ShellView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ContextMenuTest.Views"
xmlns:cal="http://www.caliburnproject.org"
mc:Ignorable="d"
Title="ShellView" Height="450" Width="800"
>
<Grid Grid.Row="1">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<DataGrid x:Name="Items" Grid.Row="0" AutoGenerateColumns="False" CanUserResizeColumns="True" CanUserAddRows="false"
VerticalAlignment="Stretch" VerticalScrollBarVisibility="Auto" MinHeight="100" SelectedItem="{Binding SelectedItem}">
<DataGrid.ContextMenu>
<ContextMenu cal:Action.TargetWithoutContext="{Binding Path=PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Add Item" cal:Message.Attach="AddItem()"/>
<MenuItem Header="Remove Item" cal:Message.Attach="RemoveItem()"/>
</ContextMenu>
</DataGrid.ContextMenu>
<DataGrid.Columns >
<DataGridTextColumn Header="ID" Binding="{Binding Path=ID, UpdateSourceTrigger=PropertyChanged}" Width="*" IsReadOnly="True"/>
<DataGridTextColumn Header="Name" Binding="{Binding Path=Name, UpdateSourceTrigger=PropertyChanged}" Width="*"/>
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<DataGrid ItemsSource="{Binding Path=SubItems}" AutoGenerateColumns="False" CanUserResizeColumns="True" CanUserAddRows="false"
VerticalAlignment="Stretch" VerticalScrollBarVisibility="Auto" MinHeight="100"
SelectedItem="{Binding Path=SelectedSubItem, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Grid}}">
<DataGrid.ContextMenu>
<ContextMenu cal:Action.TargetWithoutContext="{Binding Path=PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Add Sub Item" cal:Message.Attach="AddSubItem($dataContext)"/>
<MenuItem Header="Remove Sub Item" cal:Message.Attach="RemoveSubItem($dataContext)"/>
</ContextMenu>
</DataGrid.ContextMenu>
<DataGrid.Columns>
<DataGridTextColumn Header="ID" Binding="{Binding Path=ID}" Width="auto" IsReadOnly="True"/>
<DataGridTextColumn Header="Name" Binding="{Binding Path=Name, UpdateSourceTrigger=PropertyChanged}" Width="auto"/>
<DataGridTextColumn Header="Value" Binding="{Binding Path=Value, UpdateSourceTrigger=PropertyChanged}" Width="auto"/>
</DataGrid.Columns>
</DataGrid>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
</Grid>
</Window>
物品型号:
using Caliburn.Micro;
using System;
namespace ContextMenuTest.Models
{
public class ItemModel
{
public Guid ID { get; set; }
public string Name { get; set; }
public BindableCollection<SubItemModel> SubItems { get; set; } = new BindableCollection<SubItemModel>();
public ItemModel(Random rnd)
{
ID = Guid.NewGuid();
Name = "Item " + ID.ToString().Substring(3, 5);
for (int i = 0; i < 5; i++)
{
SubItems.Add(new SubItemModel(rnd));
}
}
}
}
子项目模型:
using System;
namespace ContextMenuTest.Models
{
public class SubItemModel
{
public Guid ID { get; set; }
public string Name { get; set; }
public int Value { get; set; }
public SubItemModel(Random rnd)
{
ID = Guid.NewGuid();
Name = "SubItem " + ID.ToString().Substring(3,5);
Value = rnd.Next();
}
}
}
尝试使用 TagHelper。它适用于您的 requirement.sample 代码如下。
<Grid Background="White" HorizontalAlignment="Stretch" Height="200" Name="GridLayout">
<ListBox x:Name="ListBoxItems">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Tag="{Binding DataContext, ElementName=GridLayout}">
<Grid.ContextMenu>
<ContextMenu Name="cm" cal:Action.TargetWithoutContext="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Open"
cal:Message.Attach="Open($dataContext)">
</MenuItem>
</ContextMenu>
</Grid.ContextMenu>
<TextBlock VerticalAlignment="Center">
.. text..
</TextBlock>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>