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_CopyMenuFlyoutItem_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 是否在&lt;ResourceDictionary.MergedDictionaries&gt;节点下? 请查看Code Sample,不确定是什么导致了这个问题。

以上是关于UWP:DataGrid、MenuFlyout 右键单击的主要内容,如果未能解决你的问题,请参考以下文章

修改 TextBox 上下文菜单/MenuFlyout

UWP CommandBar SecondaryCommand 与 AppBarButton Flyout 冲突

UWP 社区工具包 DataGrid 不显示数据

如何在 UWP c# 中用 DataTable 内容填充 DataGrid

Xamarin Form - 如何在 UWP 中为 MyToolkit.Controls.DataGrid 设置样式

UWP 社区工具包 DataGrid onecoreuap 错误