标签: relaycommand

应该如何实现`ICommand.CanExecuteChanged`?

背景

在查看 Josh Smith 关于 的文章时CommandGroup,我注意到互联网上有许多关于如何实施ICommand.CanExecuteChanged.

在 StackOverflow 上发布一个类似的问题,但是

  1. 我觉得没有明确的答案,而且
  2. 评论中没有足够的空间来添加额外的上下文。

以供参考:

  1. Josh Smith关于使用简单 .NET 事件的原始文章CommandGroup
  2. 约什-史密斯的RelayCommand使用CommandManager 实现CanExecuteChanged
  3. 微软自己的RoutedCommand使用CommandManager 实现CanExecuteChanged
  4. Microsoft 自己的 PRISM 库(版本:6)也使用了一个简单的 .NET 事件(以前的版本使用弱引用)

我的问题

我对 WPF 比较陌生,我想知道CanExecuteChanged应该如何在 Josh Smith's 中实现该事件CommandGroup以避免任何意外行为或内存泄漏?

补充阅读

Josh Smith:使用 CommandGroup 聚合 WPF 命令

Josh Smith:采用 MVVM 设计模式的 WPF 应用程序

StackOverflow:Josh Smith 的 RelayCommand 实现有缺陷吗?

StackOverflow:评论关于 CanExecuteChanged

微软:路由命令

棱镜 6:DelegateCommandBase

c# wpf weak-references mvvm relaycommand

5
推荐指数
1
解决办法
1425
查看次数

按住按钮重复命令

我的 WPF 项目中有一个按钮,当我按住按钮时,我希望它一遍又一遍地执行相同的命令。我可以使用 RepeatButton,但我的偏好是命令一旦运行完成(在它自己的任务中)就立即再次执行,而不是依赖于 RepeatButton 控件的延迟和间隔属性。

我不介意创建一个按钮单击方法,但命令操作长时间运行,执行时间将取决于 ExecuteParameter 的值(在这种情况下,代表机器物理位置的双精度元组)。

XAML:

<Button FontFamily="Marlett" FontSize="40" Content="5" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="100" Width="100" Height="50"                            
        Command="{Binding IncrBAnglePos}" 
        CommandParameter="{Binding ElementName=slider, Path=Value}">
</Button>
Run Code Online (Sandbox Code Playgroud)

C#:

SystemCommands.AddSubSystemCommand(SystemRef, CommandNames.IncrAngle, new RelayCommand(             
        o => 
        {
            double AngleIncr = (double)o > 5 ? 5 : (double)o;
            double nextX = MotionControl.LiveX;
            double nextB = MotionControl.LiveB + AngleIncr;
            nextB = nextB >= 45 ? 45 : nextB;       
                Task.Run(() =>  
                {
                    SystemCommands.ExecuteCommand(CommandNames.GotoPosition, new Tuple<double,double>(nextX, nextB));
                });
        },       
        _ => 
        {
            if (MotionControl == null)
                return false; …
Run Code Online (Sandbox Code Playgroud)

c# wpf relaycommand

5
推荐指数
1
解决办法
1042
查看次数

满足条件时,CanExecute()不启用按钮

我有一个非常简单的应用程序与a TextBox和a Button.当输入的文本TextBox长度超过5个字符时,将启用该按钮.这是我的ViewModel的代码:

private string _text { get; set; }
public string Text
{
    get { return _text; }
    set
    {
        _text = value;
        OnPropertyChanged("Text");
    }
}

private ICommand _buttonCommand;
public ICommand ButtonCommand
{
    get
    {
        if (_buttonCommand == null)
        {
            _buttonCommand = new RelayCommand(
                param => this.ButtonCommandExecute(), 
                param => this.ButtonCommandCanExecute()
            );
        }
        return _buttonCommand;
    }
}

private bool ButtonCommandCanExecute()
{
    if (this.Text.Length < 5)
    {
        return false;
    }
    else
    {
        return true;
    }
}

private …
Run Code Online (Sandbox Code Playgroud)

c# wpf relaycommand

4
推荐指数
1
解决办法
4980
查看次数

无法在MVVM Light Toolkit的RelayCommand中将单个参数传递给lambda函数

我不知道Josh Smith和Laurent Bugnion的RelayCommand的实现是否有区别,但在我看过的每一个地方,听起来像RelayCommand的Execute部分可以带0或1个参数.我只能使它与0一起工作.当我尝试类似的东西时:

public class Test
{
    public RelayCommand MyCommand { get; set; }

    public Test()
    {
        MyCommand = new RelayCommand((param) => SomeFunc(param));
    }

    private void SomeFunc( object param)
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

我收到错误:Delegate 'System.Action' does not take '1' arguments.为了确保我不是疯了,我去了RelayCommand的定义,以确保我的解决方案中没有一些流氓实现,但果然,它只是Action,而不是Action <>.

我到底在这里错过了什么?

wpf relaycommand mvvm-light

3
推荐指数
1
解决办法
2407
查看次数

我如何测试Relaycommand?

我正在阅读这篇关于MVVM的
MSDN文章.我现在正在看图#15中的RelayCommand.假装我想测试这个SaveCommand.我该怎么办?我正在使用NUnit和Rhino Mocks 3.6

c# wpf rhino-mocks mvvm relaycommand

3
推荐指数
1
解决办法
2740
查看次数

RelayCommand RaiseCanExecuteChanged()失败

我使用绑定到使用CanExecute委托初始化的RelayCommands的几个按钮.

RelayCommand DeleteCommand;
bool CanDelete()
{
    return BoolProp1 && BoolProp2;
}

...

DeleteCommand = new RelayCommand(Delete, CanDelete);
Run Code Online (Sandbox Code Playgroud)

BoolProp1并且BoolProp2是正确的属性,setter正确提升PropertyChanged,但众所周知,这还不足以使SL重新评估CanExecute命令.这就是为什么我也打电话给Delete.RaiseCanExecuteChanged()两个二传手.

所有这些工作正常(按钮被禁用并正确启用)到某一点,所有停止.在这一点上,呼叫Delete.RaiseCanExecuteChanged()不再触发我的断点CanDelete(),按钮永远保持原样.

我花了2个小时试图找出确切原因而没有效果.我怀疑RaiseCanExecuteChanged()在单个"绑定迭代"期间多次调用会以某种方式破坏机制.

任何提示?我已经在考虑使用额外的IsExecutable字段刷新INotifyPropertyChanged...

UPDATE

RelayCommand实际上是GalaSoft.MvvmLight.Command.RelayCommand来自MVVM Light Toolkit.ILSpy展示了一个非常简单的ICommand实现:

public bool CanExecute(object parameter)
{
    return this._canExecute == null || this._canExecute.Invoke();
}

public void RaiseCanExecuteChanged()
{
    EventHandler canExecuteChanged = this.CanExecuteChanged;
    if (canExecuteChanged != null)
    {
         canExecuteChanged.Invoke(this, EventArgs.Empty);
    }
}
Run Code Online (Sandbox Code Playgroud)

_canExecute …

c# silverlight mvvm relaycommand mvvm-light

3
推荐指数
1
解决办法
5696
查看次数

为什么RelayCommand <T> .Execute采用对象而不是T?

这没有做任何事情,但导致需要不必要的投射(或者更确切地说,导致我下拉代码库并自己进行更改).这样做是否有理由?

参考文献:

Codeplex上的源代码

博客发布源代码

编辑 这是一个例子:

DoCommand = new RelayCommand<AsyncCallback>((callBack) =>
{
    Console.WriteLine("In the Action<AsyncCallback>");
    SomeAsyncFunction((async_result) =>
    {
        Console.WriteLine("In the AsyncCallback");
        callBack.Invoke(new MyAsyncResult(true));
    });
});

DoCommand.Execute((iasyncresult) => Console.WriteLine(iasyncresult.IsCompleted));
//Where MyAsyncResult is a class implement IAsyncResult that sets IsCompleted in the constructor
// This will cause the "cannot cast lambda as object" error
Run Code Online (Sandbox Code Playgroud)

c# silverlight mvvm relaycommand

2
推荐指数
1
解决办法
962
查看次数

对象发送方在RelayCommand中始终为null

我正在使用RelayCommand处理按钮单击,我需要获取sender参数,但它始终为null,任何想法为什么?

ViewModel.cs

    private RelayCommand _expandClickCommand;
    public ICommand ExpandClickCommand
    {
        get
        {
            if (_expandClickCommand == null)
            {
                _expandClickCommand = new RelayCommand(ExpandClickCommandExecute, ExpandClickCommandCanExecute);
            }
            return _expandClickCommand;
        }
    }

    public void ExpandClickCommandExecute(object sender)
    {
        //sender is always null when i get here! 
    }
    public bool ExpandClickCommandCanExecute(object sender)
    {
        return true;
    }
Run Code Online (Sandbox Code Playgroud)

View.xaml

<ListBox ItemsSource="{Binding Path=MyList}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="*"/>
                    <RowDefinition Height="*"/>
                </Grid.RowDefinitions>

                <Button Grid.Column="0" Grid.Row="0" Content="Expand" Command="{Binding DataContext.ExpandClickCommand,ElementName=SprintBacklog}"/>
            </Grid>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>
Run Code Online (Sandbox Code Playgroud)

我需要在ExpandClickCommand中获取当前ListboxItem的索引

wpf mvvm relaycommand icommand

2
推荐指数
1
解决办法
5803
查看次数

为什么不工作:RelayCommand RaiseCanExecuteChanged

当我PressCommand.RaiseCanExecuteChanged();TimerOnElapsed方法中调用时,没有任何反应.

可能是什么问题呢?(GalaSoft.MvvmLight.WPF4 v4.0.30319和GalaSoft.MvvmLight.Extras.WPF4 v4.0.30319)

这是我的测试代码:

using System.Timers;
using System.Windows;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;

namespace CommandTest {


public class MainWindowVM : ViewModelBase {

    public MainWindowVM() {

        PressCommand = new RelayCommand(
                            () => MessageBox.Show("Pressed"),
                            () => _canExecute);

        PressCommand.CanExecuteChanged += (sender, args) => System.Diagnostics.Debug.WriteLine(System.DateTime.Now.ToLongTimeString() + " CanExecuteChanged");

        _timer = new Timer(1000);
        _timer.Elapsed += TimerOnElapsed;
        _timer.Enabled = true;
    }

    public RelayCommand PressCommand { get; private set; }

    #region Private

    private void TimerOnElapsed(object sender, ElapsedEventArgs elapsedEventArgs) {
        _canExecute = !_canExecute;
        PressCommand.RaiseCanExecuteChanged(); …
Run Code Online (Sandbox Code Playgroud)

relaycommand mvvm-light

2
推荐指数
1
解决办法
1698
查看次数

全面实施中继命令 - 它可以应用于所有情况吗?

我正在研究中继命令的完整实现,可以在这里找到

我听说 RelayCommand 背后的想法是拥有一种“通用遥控器”来使用您的所有命令。

如果是这样的话,我在实施方面有两个问题:

1)如果对于某些控件我不想传递参数会发生什么?我一定要吗?我是否需要相应地更改我的执行/可以执行函数以支持这些参数?

2) 如果我不想在 XAML 中传递 CommandParameter 怎么办?如果我想通过使用属性更改或代码中的其他方法来影响控件的更改。我可以在不传递 XAML 中的 CommandParameter 的情况下实现 CanExecute 或 CanExecuteChanged 吗?

到目前为止,我主要实现了部分 RelayCommands,其中 CanExecute 始终返回 true,并且我只是将控件 IsEnabled 绑定到视图模型中的额外属性。这工作得很好,但我想知道 - 完整的实施能为我做什么?

(答案能否给出完整的工作示例?)

c# wpf relaycommand

2
推荐指数
1
解决办法
1万
查看次数