使用RelayCommand时如何获得事件发送者?
我正在使用MVVM模式编写WPF应用程序,基于以下文章:使用Model-View-ViewModel设计模式的WPF应用程序
我的View上有两个按钮,按钮的"Command"属性绑定(带数据绑定)到RelayCommand类的给定实例(参见上面文章中的"图3 RelayCommand类").RelayCommand类支持检查是否可以执行给定的命令.
WPF会自动禁用无法执行命令的按钮.
我的每个命令(在ViewModel类中)都启动后台操作,并且在后台操作完成之前无法再次执行该命令.RelayCommand实例具有后台操作是否仍在工作或已完成的信息.
我的问题如下:按下任意一个按钮后,按钮自动被禁用(这是正常的),因为后台操作已经开始,命令在完成之前无法执行,但是在操作完成后,按钮不会不会自动启用,因为它们的命令"可以执行"谓词不会自动重新评估.通过让应用程序松散并重新获得焦点(通过按ALT + TAB)可以手动触发重新评估.完成此操作后,按钮再次启用.
我怎样才能以编程方式重新评估按钮命令的"可以执行"状态?
我正在使用Nuget(4.1.23.0)上可用的当前版本的MvvmLight,并且调用RaiseCanExecuteChanged似乎在单元测试中没有做任何事情.场景非常简单,我有一个命令:
public RelayCommand FooCommand { get; private set; }
Run Code Online (Sandbox Code Playgroud)
我在视图模型构造函数中新建它并将其指向一些私有方法:
FooCommand = new RelayCommand(Foo, CanFoo);
private void Foo()
{
// do some fooing.
}
private bool CanFoo()
{
return SomeRequiredProperty != null;
}
Run Code Online (Sandbox Code Playgroud)
然后在setter中SomeRequiredProperty我调用RaiseCanExecuteChanged:
public object SomeRequiredProperty
{
get
{
return someRequiredProperty;
}
set
{
someRequiredProperty = value;
FooCommand.RaiseCanExecuteChanged();
}
}
Run Code Online (Sandbox Code Playgroud)
现在在单元测试中,我执行以下操作:
// Arrange
var canExecuteChanged = false;
viewModel.FooCommand.CanExecuteChanged += (sender, args) => canExecuteChanged = true;
// Act
viewModel.SomeRequiredProperty = new object();
// Assert
Assert.That(canExecuteChanged, Is.True);
Run Code Online (Sandbox Code Playgroud)
测试失败,因为我的事件处理程序没有触发.这是为什么?
更新: …
我使用GalaSoft的RelayCommand遇到了一些问题.
我有一个可以工作的NextCommand属性,但只有几次.
之后,它完全停止工作.
您可以使用示例项目尝试此操作:
http://s000.tinyupload.com/?file_id=65828891881629261404
行为如下:
复制步骤:
所需的重复次数(复制错误)是不一致的.
有时我会在重复4次后得到它; 其他时间到9.

// Items Collection
public class ItemCollection : ViewModelBase
{
// List of Items
private readonly ObservableCollection<Item> _items = new ObservableCollection<Item>();
public ObservableCollection<Item> Items
{
get { return _items; }
}
// Constructor
public ItemCollection()
{
BackCommand = new RelayCommand(
() =>
{
// Go to previous page
var index = Items.IndexOf(ActiveItem); …Run Code Online (Sandbox Code Playgroud) 这是我在View.xaml.cs中的代码:
private RelayCommand _closeCommand;
public ICommand CloseCommand
{
get
{
if (_closeCommand == null)
{
_closeCommand = new RelayCommand(param => this.OnClose());
}
return _closeCommand;
}
}
public void OnClose()
{
Close();
}
Run Code Online (Sandbox Code Playgroud)
以下是我的View.xaml中的一些代码:
<Window.ContextMenu>
<ContextMenu>
<MenuItem Name="menuItem_Close" Header="Close" Command="{Binding CloseCommand}" />
</ContextMenu>
</Window.ContextMenu>
Run Code Online (Sandbox Code Playgroud)
当我运行程序并选择关闭菜单项时,没有任何反应.CloseCommand代码甚至没有被执行.
我想知道我是否可以像这样在我的ViewModel上创建一个RelayCommand:
public RelayCommand<IList<VectorViewModel>> MyCommand { get; set; }
Run Code Online (Sandbox Code Playgroud)
构造函数:
MyCommand = new RelayCommand<IList<VectorViewModel>>(DoSomething);
Run Code Online (Sandbox Code Playgroud)
从XAML背后的代码中,我从DataGrid中获取所选行并将它们放入List中.
if (xamDatagridVector.SelectedItems.Records.Count >= 3)
{
var list = new List<VectorViewModel>();
foreach (DataRecord record in xamDatagridVector.SelectedItems.Records)
{
list.Add((VectorViewModel)record.DataItem);
}
}
Run Code Online (Sandbox Code Playgroud)
在这个阶段,我想通过使用我之前创建的RelayCommand将List发送回ViewModel.是否可以在代码中创建一个RelayCommand并将其绑定到ViewModel的命令并将其关闭?
有什么替代方式?我当然可以在MVVM-Light中使用弱引用的Messenger类,但是我不喜欢的是它会将它发送给该调用的所有订阅者,而不仅仅是底层的ViewModel(当你有几个时它使用Messenger是致命的TabControls中相同View的实例)
我希望有人有想法让我继续前进,非常感谢,Kave
我刚学习WPF中的MVVM,我对WPF和MVVM都是全新的(我理解它是如何工作的,但从未使用它......)
我在网上找到的每一篇教程/文章都使用了RelayCommand或DelegateCommand.
在我的观察中,这些模式迫使VM违反SRP原则,因为它将把命令逻辑保存在其中.
为什么不使用ICommand接口的自定义实现?像这样:
想象一下,您正在显示一个人并将其保存到数据库中:
我的Xaml就是这样的:
<StackPanel>
<TextBlock Width="248" Height="24" Text="The name is:: " />
<TextBlock Width="248" Height="24" Text="{Binding Name}">
</TextBlock>
<TextBox HorizontalAlignment="Left" Name="textBox1" Width="120" Height="23"
VerticalAlignment="Top" Text="{Binding Name}"
/>
<Button Name="Salvar" VerticalAlignment="Bottom"
Command="{Binding SavePerson}"
CommandParameter="{Binding}">Save</Button>
</StackPanel>
Run Code Online (Sandbox Code Playgroud)
这是我的VM:
public class PersonVM: INotifyPropertyChanged
{
private string nameValue;
public string Name
{
get{
return nameValue;
}
set
{
if (value != this.nameValue)
{
this.nameValue= value;
NotifyPropertyChanged("Name");
}
}
}
public ICommand SavePerson{ get { return new SavePersonCommand(); } }
#region INotifyPropertyChanged Members …Run Code Online (Sandbox Code Playgroud) 我有以下代码:
<DataGridTemplateColumn Header="Security">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Name="Security" Content="{Binding Path=totalSecurities}" Command="{Binding Source={StaticResource viewModel}, Path=filterGridCommand}">
<Button.CommandParameter>
<MultiBinding Converter="{StaticResource PassThroughConverter}">
<Binding Path="sector"/>
<Binding ElementName="Security" Path="Name"/>
</MultiBinding>
</Button.CommandParameter>
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Run Code Online (Sandbox Code Playgroud)
以下是PassThroughConverter的代码:
public class PassThroughConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameters, CultureInfo culture)
{
return values;
}
public object[] ConvertBack(object value, Type[] targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Run Code Online (Sandbox Code Playgroud)
当我在命中返回值行时调试,正确的值在数组中,但是当我按下触发filtergrid命令的按钮时,返回的值都是null?谁能帮忙.谢谢.
尝试使用下面的RelayCommand类我收到错误消息:"名称"CommandManager"在当前上下文中不存在".根据这篇文章,类库无法识别CommandManager类,我试图通过在"添加引用"上添加一个名为PresentationCore的程序集来解决问题.不幸的是"机器上没有找到框架组件".我卸载了Microsoft.NETCore.UniversalWindowsPlatform并按照一些帖子中的建议重新安装它,我修复了Visual Studio,但这并没有改变任何东西.这是我的失败还是一个错误?作为一个新手,我总是倾向于认为我忽略了一些东西;-)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace MyApplication.Viewmodels
{
public class RelayCommand : ICommand
{
private readonly Action<object> _Execute;
private readonly Func<object, bool> _CanExecute;
public RelayCommand(Action<object> execute)
: this(execute, null)
{
}
public RelayCommand(Action<object> execute, Func<object, bool> canExecute)
{
if (execute == null)
{
throw new ArgumentNullException("execute", "Execute cannot be null.");
}
_Execute = execute;
_CanExecute = canExecute;
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; } …Run Code Online (Sandbox Code Playgroud) 一个非常常见的实现RelayCommand似乎包括以下几行:
public event EventHandler CanExecuteChanged
{
add
{
CommandManager.RequerySuggested += value;
}
remove
{
CommandManager.RequerySuggested -= value;
}
}
Run Code Online (Sandbox Code Playgroud)
这对我来说似乎非常有缺陷,因为它CommandManager是一个WPF组件,通常我的命令位于viewmodel类中.由于viewmodel不应该知道视图并且应该使用不同的框架等,这对我来说似乎很奇怪.例如,如果将viewmodel分离到一个不知道WPF名称空间(例如PCL)的额外项目中,则甚至不可能实现此实现.
此实现是否违反了MVVM模式?
或者您可能会RelayCommand以某种方式放置在您的视图中?
如果确实存在缺陷,是否有解决此问题的最佳实践实施?
relaycommand ×10
wpf ×8
mvvm ×6
c# ×4
mvvm-light ×4
.net ×3
command ×2
data-binding ×1
icommand ×1
menuitem ×1