【问题标题】:UWP: DataGrid, MenuFlyout right-clickUWP:DataGrid、MenuFlyout 右键单击
【发布时间】: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);
}

【问题讨论】:

    标签: uwp datagrid xamarin.uwp windows-community-toolkit


    【解决方案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,不确定是什么导致了这个问题。
    猜你喜欢
    • 2012-11-06
    • 1970-01-01
    • 2011-01-11
    • 2020-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-08
    相关资源
    最近更新 更多