繁体   English   中英

WPF MVVM RelayCommand每个DataGrid行上的多个按钮,仅为所选行设置启用/禁用按钮状态

[英]WPF MVVM RelayCommand multiple buttons on each DataGrid row, set enabled/disabled button state for selected row only

WPF

MVVM

RelayCommands

DataGrid,每行有多个按钮。

目标:当我单击“开始”按钮时,仅启用和禁用所选行的某些按钮

当前行为:当我单击“开始”按钮时,所有行的按钮都会启用和禁用

在此图像中,您可以看到我单击了“开始”按钮并触发了命令并正确设置了其他按钮的启用/禁用状态,但它将其应用于所有行。

我一直试图让它只申请选定的项目。 我正在尝试将参数传递给RelayCommand,如果有人可以告诉我该怎么做,也许它会起作用。

在此输入图像描述

XAML

<DataGrid x:Name="dataGridThreadView" Grid.Row="1" Grid.Column="0" AutoGenerateColumns="False" 
                  IsReadOnly="True" CanUserResizeRows="False" CanUserReorderColumns="True" Margin="4"  
                  CanUserAddRows="False" CanUserDeleteRows="False" CanUserSortColumns="True" 
                  EnableRowVirtualization="True" ItemsSource="{Binding Threads}"
                  SelectedItem="{Binding Path=SelectedThread, Mode=TwoWay}">

            <DataGrid.Columns>
                <DataGridTextColumn Header="Name"
                        Binding="{Binding Thread.Name}"/>
                <DataGridTemplateColumn Header="Actions">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <StackPanel Orientation="Horizontal" Margin="2">
                                <Button Name="buttonStartThread" Content="Start" Command="{Binding ElementName=dataGridThreadView,  Path=DataContext.StartCommand}" CommandParameter="{Binding SelectedThread}"/>
                                <Button Name="buttonSuspendThread" Content="Suspend" Command="{Binding ElementName=dataGridThreadView,  Path=DataContext.SuspendCommand}"/>
                                <Button Name="buttonResumeThread" Content="Resume" Command="{Binding ElementName=dataGridThreadView,  Path=DataContext.ResumeCommand}"/>
                                <Button Name="buttonInterruptThread" Content="Interrupt" Command="{Binding ElementName=dataGridThreadView,  Path=DataContext.InterruptCommand}"/>
                                <Button Name="buttonAbortThread" Content="Abort" Command="{Binding ElementName=dataGridThreadView,  Path=DataContext.AbortCommand}"/>
                            </StackPanel>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
        </DataGrid>

视图模型

 public class ThreadViewModel : PropertyChangedBase
{
    public ThreadModel SelectedThread { get; set; }
    public ObservableCollection<ThreadModel> Threads { get; set; }
    private bool _disableStartButton = false;
    private bool _disableSuspendButton = false;
    private bool _disableResumeButton = false;
    private bool _disableInterruptButton = false;
    private bool _disableAbortButton = false;

    public RelayCommand StartCommand { get; private set; } // should only be set once in vm during construction

    public ThreadViewModel()
    {
        _disableStartButton = false;
        _disableSuspendButton = true;
        _disableResumeButton = true;
        _disableInterruptButton = true;
        _disableAbortButton = true;
        Threads = new ObservableCollection<ThreadModel>();

        StartCommand = new RelayCommand(OnStart, CanStart);
    }

    private void OnStart(object template)
    {
        this._disableStartButton = true;
        StartCommand.RaiseCanExecuteChanged();
        _disableSuspendButton = false;
        SuspendCommand.RaiseCanExecuteChanged();
        _disableInterruptButton = false;
        InterruptCommand.RaiseCanExecuteChanged();
        _disableAbortButton = false;
        AbortCommand.RaiseCanExecuteChanged();
    }

    private bool CanStart()
    {
        return !this._disableStartButton;
    }
}

RelayCommand类

using System;
using System.Windows.Input;

namespace Multthreading
{
public class RelayCommand : ICommand
{
    Action _TargetExecuteMethod;
    Func<bool> _TargetCanExecuteMethod;

    public RelayCommand(Action executeMethod)
    {
        _TargetExecuteMethod = executeMethod;
    }

    public RelayCommand(Action executeMethod, Func<bool> canExecuteMethod)
    {
        _TargetExecuteMethod = executeMethod;
        _TargetCanExecuteMethod = canExecuteMethod;
    }

    public void RaiseCanExecuteChanged()
    {
        CanExecuteChanged(this, EventArgs.Empty);
    }
    #region ICommand Members

    bool ICommand.CanExecute(object parameter)
    {
        if (_TargetCanExecuteMethod != null)
        {
            return _TargetCanExecuteMethod();
        }
        if (_TargetExecuteMethod != null)
        {
            return true;
        }
        return false;
    }

    // Beware - should use weak references if command instance lifetime is longer than lifetime of UI objects that get hooked up to command
    // Prism commands solve this in their implementation
    public event EventHandler CanExecuteChanged = delegate { };

    void ICommand.Execute(object parameter)
    {
        if (_TargetExecuteMethod != null)
        {
            _TargetExecuteMethod();
        }
    }
    #endregion
}

public class RelayCommand<T> : ICommand
{
    Action<T> _TargetExecuteMethod;
    Func<T, bool> _TargetCanExecuteMethod;

    public RelayCommand(Action<T> executeMethod)
    {
        _TargetExecuteMethod = executeMethod;
    }

    public RelayCommand(Action<T> executeMethod, Func<T,bool> canExecuteMethod)
    {
        _TargetExecuteMethod = executeMethod;
        _TargetCanExecuteMethod = canExecuteMethod;
    }

    public void RaiseCanExecuteChanged() 
    {
         CanExecuteChanged(this, EventArgs.Empty); 
    }
    #region ICommand Members

    bool ICommand.CanExecute(object parameter)
    {
        if (_TargetCanExecuteMethod != null)
        {
            T tparm = (T)parameter;
            return _TargetCanExecuteMethod(tparm);
        }
        if (_TargetExecuteMethod != null)
        {
            return true;
        }
        return false;
    }

    // Beware - should use weak references if command instance lifetime is longer than lifetime of UI objects that get hooked up to command
    // Prism commands solve this in their implementation
    public event EventHandler CanExecuteChanged = delegate { };

    void ICommand.Execute(object parameter)
    {
        if (_TargetExecuteMethod != null)
        {
            _TargetExecuteMethod((T)parameter);
        }
    }
    #endregion
    }
}

一种可能的解决方案是使用Bindings 每一行都绑定到一个不同的项目,因此每个项目的各个属性可以绑定到按钮的属性。

您必须在对象的模型中提供额外的属性。 您可以将简单booleans绑定到按钮的IsEnabled属性。 将默认值设为false 这样您就可以编辑所选项目的属性,这应该会自动更改相应按钮的属性。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM