c# - 如何使用WPF为DataGrid上的每个记录添加删除按钮?

标签 c# wpf mvvm data-binding datagrid

我试图在DataGrid中显示记录,对于网格上的每一行,我想显示一个删除该记录的按钮。

我已将按钮成功添加到dataGrid。但是,在加载 View 时,将为每个记录调用“删除”命令。换句话说,我确认对话框会出现10次,因为我要显示10条记录。

问题
如何防止每次都执行该命令,而仅允许它在单击按钮时运行?
另外,如何将最后两列一直移到最右边,使它们垂直对齐?

在我的ViewModel中,我添加了以下命令

public ICommand DeleteVendor
{
    get
    {
        MessageBoxResult confirmation = MessageBox.Show("Are you sure?", "Delete Confirmation", MessageBoxButton.YesNo);

        bool processDelete = (confirmation == MessageBoxResult.Yes);

        return new ActionCommand(p => HandleDeleteVendor(), p => processDelete);
    }
}

private void HandleDeleteVendor()
{
    if (SelectedVendor == null)
    {
        throw new Exception("No vendor was selected");
    }

    UnitOfWork.Vendors.Remove(SelectedVendor);
    UnitOfWork.Save();
}

然后在我看来,我添加了以下XAML代码
<DataGrid ItemsSource="{Binding Vendors}"
          SelectedItem="{Binding SelectedVendor}"
          AutoGenerateColumns="False"
          HorizontalAlignment="Stretch"
          VerticalAlignment="Center"
          CanUserAddRows="False">

    <DataGrid.Columns>

    <DataGridTextColumn Header="Name"
                            Binding="{Binding Name}" />
        <DataGridTextColumn Header="Account Number"
                            Binding="{Binding AccountCode}" />

        <DataGridTemplateColumn>
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <Button VerticalAlignment="Center"
                            Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}},
                            Path=DataContext.ShowVendor}">
                        <StackPanel Orientation="Horizontal">

                            <fa:FontAwesome Icon="Eye"
                                            FontSize="18" />
                            <Label Content="Details" 
                                   Padding="7 0 0 0" />
                        </StackPanel>
                    </Button>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>

        <DataGridTemplateColumn>
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <Button VerticalAlignment="Center"
                            Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}},
                                  Path=DataContext.DeleteVendor}">
                        <StackPanel Orientation="Horizontal">

                            <fa:FontAwesome Icon="Trash"
                                            FontSize="18" />
                            <Label Content="Delete"
                                   Padding="7 0 0 0" />
                        </StackPanel>
                    </Button>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>

    </DataGrid.Columns>

</DataGrid> 

如果需要,这里是我的ICommand实现
public sealed class ActionCommand : ICommand
{
    private readonly Action<Object> Action;
    private readonly Predicate<Object> Allowed;

    /// <summary>
    /// Initializes a new instance of the <see cref="ActionCommand"/> class.
    /// </summary>
    /// <param name="action">The <see cref="Action"/> delegate to wrap.</param>
    public ActionCommand(Action<Object> action)
        : this(action, null)
    {
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="ActionCommand"/> class.
    /// </summary>
    /// <param name="action">The <see cref="Action"/> delegate to wrap.</param>
    /// <param name="predicate">The <see cref="Predicate{Object}"/> that determines whether the action delegate may be invoked.</param>
    public ActionCommand(Action<Object> action, Predicate<Object> allowed)
    {
        if (action == null)
        {
            throw new ArgumentNullException("action", "You must specify an Action<T>.");
        }

        Action = action;
        Allowed = allowed;
    }

    /// <summary>
    /// Defines the method that determines whether the command can execute in its current state.
    /// </summary>
    /// <returns>
    /// true if this command can be executed; otherwise, false.
    /// </returns>
    /// <param name="parameter">Data used by the command.  If the command does not require data to be passed, this object can be set to null.</param>
    public bool CanExecute(object parameter)
    {
        if (Allowed == null)
        {
            return true;
        }

        return Allowed(parameter);
    }

    /// <summary>
    /// Defines the method to be called when the command is invoked.
    /// </summary>
    /// <param name="parameter">Data used by the command.  If the command does not require data to be passed, this object can be set to null.</param>
    public void Execute(object parameter)
    {
        Action(parameter);
    }

    /// <summary>
    /// Executes the action delegate without any parameters.
    /// </summary>
    public void Execute()
    {
        Execute(null);
    }

    /// <summary>
    /// Occurs when changes occur that affect whether the command should execute.
    /// </summary>
    public event EventHandler CanExecuteChanged
    {
        add
        {
            if (Allowed != null)
            {
                CommandManager.RequerySuggested += value;
            }
        }
        remove
        {
            if (Allowed != null)
            {
                CommandManager.RequerySuggested -= value;
            }
        }
    }

    /// <summary>
    /// Raises the <see cref="CanExecuteChanged" /> event.
    /// </summary>
    public void RaiseCanExecuteChanged()
    {
        CommandManager.InvalidateRequerySuggested();
    }

}

最佳答案

确认应该是delete方法的一部分,而不是命令定义的一部分:

public ICommand DeleteVendor
{
    get
    {
        return new ActionCommand(p => HandleDeleteVendor(), p => SelectedVendor != null);
    }
}

private void HandleDeleteVendor()
{
    MessageBoxResult confirmation = MessageBox.Show("Are you sure?", "Delete Confirmation", MessageBoxButton.YesNo);

    if (confirmation != MessageBoxResult.Yes);
       return;

    if (SelectedVendor == null)
    {
        // IMO, it is better to handle this situation gracefully and show messageBox with a warning
        throw new Exception("No vendor was selected");
    }

    UnitOfWork.Vendors.Remove(SelectedVendor);
    UnitOfWork.Save();
}

关于c# - 如何使用WPF为DataGrid上的每个记录添加删除按钮?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48855438/

相关文章:

javascript - 两种方式的数据绑定(bind)不适用于 knockout ObservableArrays

.net - 使用MVVM和WPF显示项目的一致值

c# - WPF XAML 解析错误。 "Data at the root level is invalid."

c# - 获取 nuget 包目录的位置

c# - 以编程方式添加控件时如何使控件彼此保持一定距离?

c# - "{{" "}}"之间的紫色文本是什么

c# - 使用 C# 添加 entityFramework 部分

c# - Xamarin Forms - 点击标签时打开多个页面

c# - WPF 网页浏览器 : changing IE print dialog properties programmatically

.net - TabControl.Items.Remove(TabItem) 不会释放 TabItem 使用的内存