Я разрабатываю приложение WinUI3. Я хотел бы иметь сетку данных CommunityToolkit со столбцом кнопки в каждой строке. При нажатии кнопки должно появиться всплывающее окно, позволяющее пользователю вводить данные для заполнения этого поля.
Для простоты я поместил в пример только две кнопки, но приложению потребуется больше элементов управления:
<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>
Как показано на гифке, у меня проблемы с фокусировкой при нажатии. Первый щелчок работает как чудо, дальнейшее нажатие, похоже, переводит ячейку в режим редактирования, и всплывающее окно не запускается. Если я изменю фокус на другие строки/ячейки, результаты каждый раз будут разными.
Я думаю, что существует механизм редактирования/пропуска кликов, которого я не знаю, как избежать. Перевод ячейки в режим «IsReadOnly» не меняет поведение.
Если я попытаюсь использовать MenuFlyout или ContextFlyout в ячейке, это работает отлично, но мне нужно показать больше элементов управления, а не простое меню, которое будет запускаться при щелчке правой кнопкой мыши.
Раньше у DataGridComboBoxColumn
была такая же проблема , и вы можете увидеть здесь, как она была исправлена.
Вы можете создать собственные DataGrid
и Column
и применить аналогичное исправление следующим образом:
ОБНОВЛЯТЬ
Я обновил свой ответ таким образом, чтобы вы могли отменить режим редактирования явно, когда Flyout
закрыт.
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;
}
}
}
и используйте его следующим образом:
<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>
Ты прав. Я обновил свой ответ таким образом, чтобы вы могли отменить режим редактирования явно, когда Flyout
закрыт.
Еще раз спасибо за обновление вашего ответа. Работает хорошо. Я считаю довольно глупой необходимость переопределять DataGrid только для того, чтобы кнопка работала. Я имею в виду, что я нахожусь в режиме редактирования, кнопка создана и находится сверху, и она должна получать клики.
Большое спасибо, таким образом всплывающее окно появляется каждый раз, когда ячейка переходит в режим редактирования. К сожалению, если ячейка уже находится в режиме редактирования, постоянное нажатие вызывает ту же проблему. Кнопка «Мне нравится» не запускает всплывающее окно. Я попробовал зарегистрироваться на событие клика и сделал
Flyout.ShowAt
, но безуспешно.