UWP:DataGrid、MenuFlyout 右键单击
Posted
技术标签:
【中文标题】UWP:DataGrid、MenuFlyout 右键单击【英文标题】:UWP: DataGrid, MenuFlyout right-click 【发布时间】:2019-07-13 03:26:54 【问题描述】:问题: 右键单击一行时,我正在尝试在 DataGrid 上创建一个菜单。
目标: 右键单击一行时是否可以在 DataGrid 上创建菜单;我可以在单元格上创建一个吗?
<controls:DataGridTemplateColumn Header="OrderId">
<controls:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid>
<Grid.ContextFlyout>
<MenuFlyout>
<MenuFlyoutItem Text="Copy" Icon="Copy" Click="MenuFlyoutItem_Copy" />
<MenuFlyoutSeparator />
<MenuFlyoutItem Text="Delete" Icon="Delete" Click="MenuFlyoutItem_Delete" />
</MenuFlyout>
</Grid.ContextFlyout>
<TextBlock Text="Binding OrderId" />
</Grid>
</DataTemplate>
</controls:DataGridTemplateColumn.CellTemplate>
</controls:DataGridTemplateColumn>
private void MenuFlyoutItem_Copy(object sender, RoutedEventArgs e)
ObservableCollection<SampleOrder> dataGrid = DataGrid.ItemsSource as ObservableCollection<SampleOrder>;
MenuFlyoutItem mfi = sender as MenuFlyoutItem;
SampleOrder seleted = mfi.DataContext as SampleOrder;
var copiedItem = (SampleOrder)seleted.Clone();
dataGrid.Add(copiedItem);
private void MenuFlyoutItem_Delete(object sender, RoutedEventArgs e)
ObservableCollection<SampleOrder> dataGrid = DataGrid.ItemsSource as ObservableCollection<SampleOrder>;
MenuFlyoutItem mfi = sender as MenuFlyoutItem;
SampleOrder seleted = mfi.DataContext as SampleOrder;
dataGrid.Remove(seleted);
【问题讨论】:
【参考方案1】:除非我遗漏了什么,否则这比 Nico 的回答要容易得多。您需要做的就是像这样设置RowStyle
属性:
<controls:DataGrid.RowStyle>
<Style TargetType="controls:DataGridRow">
<Setter Property="controls:DataGridRow.ContextFlyout">
<Setter.Value>
<MenuFlyout>
<MenuFlyoutItem x:Name="MyMenuItem"
Click="MyMenuItem_Click"
Text="Do Things" />
</MenuFlyout>
</Setter.Value>
</Setter>
</Style>
</controls:DataGrid.RowStyle>
然后在你的处理程序中:
private void MyMenuItem_Click(object sender, RoutedEventArgs e)
var item = (sender as FrameworkElement).DataContext as MyModel;
// Do things with your item.
【讨论】:
我似乎没有获得右击行的模型,而是获得了整个页面的 ViewModel:/ 知道为什么会这样吗? (我使用的是 WinUI3 而不是 UWP。) 我的错,我在 DataGrid 上而不是在 RowStyle 中设置 ContextFlyout。 这个解决方案非常适合我。但是,我可以在右键单击 DataGrid 行时选择它以切换菜单条目吗? @ZipGenius 我现在不能自己尝试,但根据记忆,您可能想要(sender as MenuFlyoutItem).ContextFlyout.Target
之类的东西。【参考方案2】:
如果要在行中添加MenuFlyout
,则需要自定义行样式并将ContextFlyout
添加到DataGridCellsPresenter
。
<localprimitives:DataGridCellsPresenter x:Name="CellsPresenter" Grid.Column="1"
localprimitives:DataGridFrozenGrid.IsFrozen="True" MinHeight="32"
AutomationProperties.AccessibilityView="Raw">
<localprimitives:DataGridCellsPresenter.ContextFlyout>
<MenuFlyout>
<MenuFlyoutItem Text="Copy" Icon="Copy" Click="MenuFlyoutItem_Copy" />
<MenuFlyoutSeparator />
<MenuFlyoutItem Text="Delete" Icon="Delete" Click="MenuFlyoutItem_Delete" />
</MenuFlyout>
</localprimitives:DataGridCellsPresenter.ContextFlyout>
</localprimitives:DataGridCellsPresenter>
以下是完整的DataGridRow
样式,可以直接使用
<Style TargetType="controls:DataGridRow">
<Setter Property="IsTabStop" Value="False" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:DataGridRow">
<localprimitives:DataGridFrozenGrid x:Name="RowRoot">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Rectangle
x:Name="BackgroundRectangle"
Grid.ColumnSpan="2"
Fill="ThemeResource SystemControlTransparentBrush"
/>
<Rectangle
x:Name="InvalidVisualElement"
Grid.ColumnSpan="2"
Fill="ThemeResource DataGridRowInvalidBrush"
Opacity="0"
/>
<localprimitives:DataGridRowHeader
x:Name="RowHeader"
Grid.RowSpan="3"
localprimitives:DataGridFrozenGrid.IsFrozen="True"
/>
<localprimitives:DataGridCellsPresenter
x:Name="CellsPresenter"
Grid.Column="1"
MinHeight="32"
localprimitives:DataGridFrozenGrid.IsFrozen="True"
AutomationProperties.AccessibilityView="Raw"
>
<localprimitives:DataGridCellsPresenter.ContextFlyout>
<MenuFlyout>
<MenuFlyoutItem
Click="MenuFlyoutItem_Copy"
Icon="Copy"
Text="Copy"
/>
<MenuFlyoutSeparator />
<MenuFlyoutItem
Click="MenuFlyoutItem_Delete"
Icon="Delete"
Text="Delete"
/>
</MenuFlyout>
</localprimitives:DataGridCellsPresenter.ContextFlyout>
</localprimitives:DataGridCellsPresenter>
<localprimitives:DataGridDetailsPresenter
x:Name="DetailsPresenter"
Grid.Row="1"
Grid.Column="1"
AutomationProperties.AccessibilityView="Raw"
Background="ThemeResource DataGridDetailsPresenterBackgroundBrush"
/>
<Rectangle
x:Name="BottomGridLine"
Grid.Row="2"
Grid.Column="1"
Height="1"
HorizontalAlignment="Stretch"
/>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="NormalAlternatingRow" />
<VisualState x:Name="PointerOver">
<Storyboard>
<ColorAnimation
Storyboard.TargetName="BackgroundRectangle"
Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
To="ThemeResource SystemListLowColor"
Duration="0"
/>
</Storyboard>
</VisualState>
<VisualState x:Name="NormalSelected">
<Storyboard>
<ColorAnimation
Storyboard.TargetName="BackgroundRectangle"
Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
To="ThemeResource DataGridRowSelectedBackgroundColor"
Duration="0"
/>
<DoubleAnimation
Storyboard.TargetName="BackgroundRectangle"
Storyboard.TargetProperty="Opacity"
To="ThemeResource DataGridRowSelectedBackgroundOpacity"
Duration="0"
/>
</Storyboard>
</VisualState>
<VisualState x:Name="PointerOverSelected">
<Storyboard>
<ColorAnimation
Storyboard.TargetName="BackgroundRectangle"
Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
To="ThemeResource DataGridRowSelectedHoveredBackgroundColor"
Duration="0"
/>
<DoubleAnimation
Storyboard.TargetName="BackgroundRectangle"
Storyboard.TargetProperty="Opacity"
To="ThemeResource DataGridRowSelectedHoveredBackgroundOpacity"
Duration="0"
/>
</Storyboard>
</VisualState>
<VisualState x:Name="PointerOverUnfocusedSelected">
<Storyboard>
<ColorAnimation
Storyboard.TargetName="BackgroundRectangle"
Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
To="ThemeResource DataGridRowSelectedHoveredUnfocusedBackgroundColor"
Duration="0"
/>
<DoubleAnimation
Storyboard.TargetName="BackgroundRectangle"
Storyboard.TargetProperty="Opacity"
To="ThemeResource DataGridRowSelectedHoveredUnfocusedBackgroundOpacity"
Duration="0"
/>
</Storyboard>
</VisualState>
<VisualState x:Name="UnfocusedSelected">
<Storyboard>
<ColorAnimation
Storyboard.TargetName="BackgroundRectangle"
Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
To="ThemeResource DataGridRowSelectedUnfocusedBackgroundColor"
Duration="0"
/>
<DoubleAnimation
Storyboard.TargetName="BackgroundRectangle"
Storyboard.TargetProperty="Opacity"
To="ThemeResource DataGridRowSelectedUnfocusedBackgroundOpacity"
Duration="0"
/>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="ValidationStates">
<VisualState x:Name="Valid" />
<VisualState x:Name="Invalid">
<Storyboard>
<ObjectAnimationUsingKeyFrames
Storyboard.TargetName="BackgroundRectangle"
Storyboard.TargetProperty="Visibility"
Duration="0"
>
<DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed" />
</ObjectAnimationUsingKeyFrames>
<DoubleAnimation
Storyboard.TargetName="InvalidVisualElement"
Storyboard.TargetProperty="Opacity"
To="0.4"
Duration="0"
/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</localprimitives:DataGridFrozenGrid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
请注意该样式包含很多 ThemeResource 来自 windows-community-toolkit。在使用上述样式之前,您需要将MergedDictionaries
添加到您的应用资源中。
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ms-appx:///Microsoft.Toolkit.Uwp.UI.Controls.DataGrid/DataGrid/DataGrid.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
更新 2
获取执行菜单的行索引的正确方法是什么
@JamesEllis,您可以在MenuFlyoutItem_Copy
或MenuFlyoutItem_Delete
事件处理程序中获取行索引。请参考以下代码。
private void MenuFlyoutItem_Copy(object sender, RoutedEventArgs e)
var menu = sender as MenuFlyoutItem;
var item = menu.DataContext as Item;
var items = dataGrid.ItemsSource as List<Item>;
var index = items.IndexOf(item);
【讨论】:
好的,菜单选项可以找到..但是现在当您单击单元格编辑其数据时,UWP 应用程序崩溃了,知道可能是什么原因吗?谢谢。 你添加ms-appx:///Microsoft.Toolkit.Uwp.UI.Controls.DataGrid/DataGrid/DataGrid.xaml
到应用资源了吗?
是的,已将其添加到 App.xaml <ResourceDictionary.MergedDictionaries>
节点下?
请查看Code Sample,不确定是什么导致了这个问题。以上是关于UWP:DataGrid、MenuFlyout 右键单击的主要内容,如果未能解决你的问题,请参考以下文章
UWP CommandBar SecondaryCommand 与 AppBarButton Flyout 冲突
如何在 UWP c# 中用 DataTable 内容填充 DataGrid