Jos*_*h G 69 wpf updating mvvm
有谁知道我怎么可以强制CanExecute
调用自定义命令(约什史密斯RelayCommand
)?
通常,CanExecute
只要在UI上发生交互,就会调用它.如果我点击某些内容,我的命令会更新.
我有一种情况,CanExecute
即幕后的计时器打开/关闭条件.因为这不是由用户交互驱动的,CanExecute
所以在用户与UI交互之前不会调用.最终结果是我的Button
保持启用/禁用,直到用户点击它.点击后,它会正确更新.有时Button
显示已启用,但是当用户单击它时,更改为禁用而不是触发.
当计时器更改影响的属性时,如何强制更新代码CanExecute
?我对影响的属性尝试了kick PropertyChanged
(INotifyPropertyChanged
)CanExecute
,但这没有帮助.
示例XAML:
<Button Content="Button" Command="{Binding Cmd}"/>
Run Code Online (Sandbox Code Playgroud)
后面的示例代码:
private ICommand m_cmd;
public ICommand Cmd
{
if (m_cmd == null)
m_cmd = new RelayCommand(
(param) => Process(),
(param) => EnableButton);
return m_cmd;
}
// Gets updated from a timer (not direct user interaction)
public bool EnableButton { get; set; }
Run Code Online (Sandbox Code Playgroud)
Ken*_*art 101
CommandManager.InvalidateRequerySuggested()
Sil*_*own 28
很久以前我就知道了CommandManager.InvalidateRequerySuggested()并且使用过它,但它有时对我不起作用.我终于弄清楚为什么会这样!即使它不像其他一些动作那样抛出,你也必须在主线程上调用它.
在后台线程上调用它似乎可以工作,但有时会禁用UI.我真的希望这可以帮助别人,并节省他浪费的时间.
小智 17
解决方法是绑定IsEnabled
到属性:
<Button Content="Button" Command="{Binding Cmd}" IsEnabled="{Binding Path=IsCommandEnabled}"/>
Run Code Online (Sandbox Code Playgroud)
然后在ViewModel中实现此属性.这也使得UnitTesting更容易使用属性而不是命令来查看命令是否可以在某个时间点执行.
我个人觉得它更方便.
这个变种可能适合你:
public interface IRelayCommand : ICommand
{
void UpdateCanExecuteState();
}
Run Code Online (Sandbox Code Playgroud)
执行:
public class RelayCommand : IRelayCommand
{
public event EventHandler CanExecuteChanged;
readonly Predicate<Object> _canExecute = null;
readonly Action<Object> _executeAction = null;
public RelayCommand( Action<object> executeAction,Predicate<Object> canExecute = null)
{
_canExecute = canExecute;
_executeAction = executeAction;
}
public bool CanExecute(object parameter)
{
if (_canExecute != null)
return _canExecute(parameter);
return true;
}
public void UpdateCanExecuteState()
{
if (CanExecuteChanged != null)
CanExecuteChanged(this, new EventArgs());
}
public void Execute(object parameter)
{
if (_executeAction != null)
_executeAction(parameter);
UpdateCanExecuteState();
}
}
Run Code Online (Sandbox Code Playgroud)
使用简单:
public IRelayCommand EditCommand { get; protected set; }
...
EditCommand = new RelayCommand(EditCommandExecuted, CanEditCommandExecuted);
protected override bool CanEditCommandExecuted(object obj)
{
return SelectedItem != null ;
}
protected override void EditCommandExecuted(object obj)
{
// Do something
}
...
public TEntity SelectedItem
{
get { return _selectedItem; }
set
{
_selectedItem = value;
//Refresh can execute
EditCommand.UpdateCanExecuteState();
RaisePropertyChanged(() => SelectedItem);
}
}
Run Code Online (Sandbox Code Playgroud)
XAML:
<Button Content="Edit" Command="{Binding EditCommand}"/>
Run Code Online (Sandbox Code Playgroud)