【问题标题】:How to add a delete button for every record on a DataGrid using WPF?如何使用 WPF 为 DataGrid 上的每条记录添加删除按钮?
【发布时间】:2018-07-29 01:19:02
【问题描述】:

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

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

问题 如何防止命令每次都被执行,并且只允许它在按钮单击时运行? 另外,我怎样才能将最后 2 列一直移动到最右边,使它们垂直对齐?

在我的 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();
    }

}

【问题讨论】:

  • 您可以将当前行绑定到删除按钮的CommandPameter。然后在您的ActionCommand 中删除您从参数中检索到的记录
  • @IlVic 你能请教一些关于如何处理的代码吗?我认为您的建议将使我能够将记录传递回视图模型,以便我可以删除它。但它没有解释如何防止命令在加载时自动触发

标签: c# wpf mvvm data-binding datagrid


【解决方案1】:

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

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();
}

【讨论】:

    猜你喜欢
    • 2016-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-18
    • 2011-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多