如何使用WPF为DataGrid上的每个记录添加删除按钮? [英] How to add a delete button for every record on a DataGrid using WPF?

查看:97
本文介绍了如何使用WPF为DataGrid上的每个记录添加删除按钮?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to display record in a DataGrid and for each row on the grid, I want to show a button to delete that record.

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

I added the button successfully to the dataGrid. However, when the view is loaded, the "delete" command is called for every record. In another word, I the confirm dialog appears 10 time because I have 10 records to display.

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

Questions How to I prevent the command from being executed each time and only allow it to run on button click? Also, how can I move the last 2 column all the way to the far right so they are vertically aligned?

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

In my ViewModel, I added the following command

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 代码

Then in my view I added the following XAML code

<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 实现

If needed here is my ICommand implementation

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

}


推荐答案

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

confirmation should be a part of delete method, not a part of command definition:

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

这篇关于如何使用WPF为DataGrid上的每个记录添加删除按钮?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆