题
有谁知道我怎么能强迫CanExecute
得到叫上一个自定义命令(约什 - 史密斯的的 RelayCommand
)?
典型地,每当相互作用在UI上发生CanExecute
被调用。如果我点击的东西,我的命令被更新。
我有其中用于CanExecute
条件被接通/断开由幕后的定时器接通得到的情况。因为这不是通过用户交互驱动,CanExecute
不叫,直到用户与UI交互。最终的结果是,我的Button
保持启用/禁用,直到用户点击它。点击之后,它被正确地更新。有时出现Button
启用,但当用户点击它改变为禁用,而不是点火。
我怎么能强制代码的更新时,计时器变化影响CanExecute
的财产?我试图射击影响PropertyChanged
财产INotifyPropertyChanged
(CanExecute
),但是这并没有帮助。
实施例XAML:
<Button Content="Button" Command="{Binding Cmd}"/>
实施例后面的代码:
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; }
其他提示
我知道CommandManager.InvalidateRequerySuggested的()很久以前,并用它,但它不是有时为我工作。我终于想通了,为什么是这种情况!即使它不会引发像其他一些动作,你必须把它在主线程上。
调用它在后台线程会出现工作,但有时会离开禁用UI。我真的希望这可以帮助别人,并保存他们,我只是浪费了时间。
一个用于该替代方法结合IsEnabled
到一个属性:
<Button Content="Button" Command="{Binding Cmd}" IsEnabled="{Binding Path=IsCommandEnabled}"/>
,然后实现在您的视图模型此属性。这也使得更容易一点为单元测试与属性而不是命令的工作,看该命令是否可以在特定的时间点被执行。
我个人觉得它更方便。
也许这变种会适合你:
public interface IRelayCommand : ICommand
{
void UpdateCanExecuteState();
}
实现:
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();
}
}
使用简单的:
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);
}
}
XAML:
<Button Content="Edit" Command="{Binding EditCommand}"/>
由于球员的提示。下面是关于如何从BG线程封送调用UI线程一些代码:
private SynchronizationContext syncCtx; // member variable
在构造:
syncCtx = SynchronizationContext.Current;
在后台线程,触发重新查询:
syncCtx.Post( delegate { CommandManager.InvalidateRequerySuggested(); }, null );
希望有所帮助。
- 迈克尔
要更新只有一个GalaSoft.MvvmLight.CommandWpf.RelayCommand你可以使用
mycommand.RaiseCanExecuteChanged();
和对我来说我已经创建的扩展方法:
public static class ExtensionMethods
{
public static void RaiseCanExecuteChangedDispatched(this RelayCommand cmd)
{
System.Windows.Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() => { cmd.RaiseCanExecuteChanged(); }));
}
public static void RaiseCanExecuteChangedDispatched<T>(this RelayCommand<T> cmd)
{
System.Windows.Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() => { cmd.RaiseCanExecuteChanged(); }));
}
}