Я решил эту проблему, создав класс DelegateCommand. Он выглядит в точности как RelayCommand (см. Джош Смит), за исключением того, что он позволяет обновлять обратные вызовы.
public class DelegateCommand : ICommand
{
Action<object> _execute;
Predicate<object> _canExecute;
#region Constructors
public DelegateCommand()
{
}
public DelegateCommand(Action<object> execute)
: this(execute, null)
{
}
public DelegateCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
#endregion // Constructors
public void Delegate(Action<object> execute)
{
_execute = execute;
}
public void Delegate(Action<object> execute, Predicate<object> canExecute)
{
_execute = execute;
_canExecute = canExecute;
}
#region ICommand Members
[DebuggerStepThrough]
public bool CanExecute(object parameter)
{
return _canExecute == null ? _execute != null : _canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
if (CanExecute(parameter))
_execute(parameter);
}
#endregion // ICommand Members
}
Затем я создал класс для хранения статических команд приложения.
public class CustomCommands
{
private readonly static DelegateCommand admin;
static CustomCommands()
{
admin = new DelegateCommand();
}
public static DelegateCommand AdminCommand
{
get { return admin; }
}
}
Затем я добавил привязку клавиш к главному окну, поскольку пользовательские элементы управления не получают жестов клавиш.
<Window.InputBindings>
<KeyBinding Key="A" Modifiers="Control" Command="my:CustomCommands.AdminCommand"/>
</Window.InputBindings>
Затем в моей ViewModel я могу обработать событие следующим образом:
public class OfflineViewModel : ViewModelBase
{
public OfflineViewModel()
{
CustomCommands.AdminCommand.Delegate(ShowAdmin);
}
public override void Removed()
{
base.Removed();
ReleaseAdminCommand();
}
public override void Hidden()
{
base.Hidden();
ReleaseAdminCommand();
}
void HookAdminCommand()
{
CustomCommands.AdminCommand.Delegate(ShowAdmin);
}
void ReleaseAdminCommand()
{
// Remove handling
CustomCommands.AdminCommand.Delegate(null, null);
}
void ShowAdmin(object parameter)
{
Navigation.Push(new AdminViewModel());
}
}
При желании я мог бы использовать события внутри DelegateCommand.