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
}
}
答案 0 :(得分:0)
可能的解决方案是使用Bindings
。
每一行都绑定到一个不同的项目,因此每个项目的各个属性可以绑定到按钮的属性。
您必须在对象的模型中提供额外的属性。您可以将简单booleans
绑定到按钮的IsEnabled
属性。将默认值设置为 false 。
这样您就可以编辑所选项目的属性,这应该会自动更改相应按钮的属性。