fasigno
fasigno

Reputation: 3

WinUI3 Datagrid TemplatedColumn with flyout button

I'm developing a WinUI3 application. I'd like to have a CommunityToolkit datagrid with a button column each row. When the button is clicked a flyout needs to show up letting user enters the data to populate that field.

For simplicity I put only two buttons in the example but the application will require more controls:

<controls:DataGridTemplateColumn Header="Value" IsReadOnly="True">
    <controls:DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <Grid>
                <Button Content="{Binding Value}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
                    <Button.Flyout>
                        <Flyout>
                            <StackPanel>
                                <TextBlock Text="All items will be removed. Do you want to continue?" Margin="0,0,0,12" />
                                <Button Content="Yes, empty my cart" Click="Button_Click" />
                                <Button Content="No, cart is full" Click="FullButton_Click" />
                            </StackPanel>
                        </Flyout>
                    </Button.Flyout>
                </Button>
            </Grid>
        </DataTemplate>
    </controls:DataGridTemplateColumn.CellTemplate>
</controls:DataGridTemplateColumn>

Gif

As shown in the gif I've got clicking focus issues. First click works like a charm, further clicking seems to put cell in edit mode and flyout is not triggered. If I change the focus on other rows / cells results are different each time.

I think there's an editing / click pass through mechanism that I don't know how to avoid. Putting cell in "IsReadOnly" mode doesn't change the behaviour.

If I try to use a MenuFlyout or ContextFlyout on the cell it works great, but I need to show more controls and not a simple menu to be triggered on right click.

Upvotes: 0

Views: 283

Answers (1)

Andrew KeepCoding
Andrew KeepCoding

Reputation: 13726

The DataGridComboBoxColumn used to have the same issue and you can see here how it was fixed.

You can create a custom DataGrid and Column and apply a similar fix like this:

UPDATE

I updated my answer in way that you can cancel the edit mode explictly when the Flyout is closed.

public class DataGridButtonWithFlyoutColumn : DataGridTemplateColumn
{
    public event EventHandler<object>? FlyoutClosed;

    protected override object PrepareCellForEdit(FrameworkElement editingElement, RoutedEventArgs editingEventArgs)
    {
        if (editingElement is Button button)
        {
            button.Flyout.ShowAt(button);
            button.Flyout.Closed += (s, e) =>
            {
                this.FlyoutClosed?.Invoke(this, e);
            };
        }

        return base.PrepareCellForEdit(editingElement, editingEventArgs);
    }
}
public class DataGridEx : DataGrid
{
    public DataGridEx()
    {
        this.BeginningEdit += DataGridEx_BeginningEdit;
    }

    private void DataGridEx_BeginningEdit(object? sender, DataGridBeginningEditEventArgs e)
    {
        if (e.Column is DataGridButtonWithFlyoutColumn column)
        {
            column.FlyoutClosed += DataGridButtonWithFlyoutColumn_FlyoutClosed;
        }
    }

    private void DataGridButtonWithFlyoutColumn_FlyoutClosed(object? sender, object e)
    {
        _ = CancelEdit();

        if (sender is DataGridButtonWithFlyoutColumn column)
        {
            column.FlyoutClosed -= DataGridButtonWithFlyoutColumn_FlyoutClosed;
        }
    }
}

and use it like this:

<local:DataGridEx
    x:Name="DataGridControl"
    ItemsSource="{x:Bind Items}">
    <toolkit:DataGrid.Columns>
        <toolkit:DataGridTextColumn
            Binding="{Binding Name}"
            Header="Name" />
        <toolkit:DataGridComboBoxColumn
            Binding="{Binding Type}"
            Header="Type"
            ItemsSource="{x:Bind Types, Mode=OneWay}" />
        <local:DataGridButtonWithFlyoutColumn Header="Value">
            <local:DataGridButtonWithFlyoutColumn.CellTemplate>
                <DataTemplate>
                    <Grid Background="LightGreen">
                        <TextBlock
                            HorizontalAlignment="Stretch"
                            VerticalAlignment="Center"
                            HorizontalTextAlignment="Center"
                            Text="{Binding Value}" />
                    </Grid>

                </DataTemplate>
            </local:DataGridButtonWithFlyoutColumn.CellTemplate>
            <toolkit:DataGridTemplateColumn.CellEditingTemplate>
                <DataTemplate>
                    <Button
                        HorizontalAlignment="Stretch"
                        VerticalAlignment="Stretch"
                        Background="HotPink"
                        Content="{Binding Value}"
                        FontWeight="ExtraBold">
                        <Button.Flyout>
                            <Flyout>
                                <StackPanel>
                                    <TextBlock
                                        Margin="0,0,0,12"
                                        Text="All items will be removed. Do you want to continue?" />
                                    <Button
                                        Click="Button_Click"
                                        Content="Yes, empty my cart" />
                                    <Button
                                        Click="Button_Click_1"
                                        Content="No, cart is full" />
                                </StackPanel>
                            </Flyout>
                        </Button.Flyout>
                    </Button>
                </DataTemplate>
            </toolkit:DataGridTemplateColumn.CellEditingTemplate>
        </local:DataGridButtonWithFlyoutColumn>
    </toolkit:DataGrid.Columns>
</local:DataGridEx>

Upvotes: 0

Related Questions