Прежде всего извините за мой "пиджин" английский,: (
Приложение было построено по шаблону MVVM. ViewModel предоставляет свои функциональные возможности с помощью команд и имеет специальную команду - DispatchCommand, которая получает (в CommandParameter) пару других команд / параметров и выполняет полученную команду с полученным параметром. Функция (довольно неважная для тематических целей) состоит в том, что DispatcherCommand выполняется в основном потоке приложения, другие команды ViewModel (вызываемые DispatcherCommand) являются асинхронными, и каждая из них выполняет свой делегат Execute () в отдельном потоке. Такой подход (косвенное выполнение асинхронных команд ViewModel через DispatchCommand), используемый для управления внутренним состоянием ViewModel (например, DispatchCommands отказывается от вызова конкретной асинхронной команды, в то время как другая асинхронная команда выполняет и т. Д.).
В коде это выглядит так:
// Dispatcher command
public class DispatcherCommand : ICommand { }
// async command
public interface IAsyncCommand : ICommand { }
public class AsyncCommand : IAsyncCommand { }
// view model
public class AsyncModel
{
public DispatcherCommand Dispatcher { get {...} }
// async commands - current model capabilities
public AsyncCommand FirstCapability { get {...} }
public AsyncCommand SecondCapability { get {...} }
...
}
// using example
AsyncModel model = new AsyncModel();
model.Dispatcher.Execute(
new { Command = model.FirstCapability, Parameter = "string param" });
Я хочу предоставить доступ к асинхронным командам в XAML таким же образом:
<Button Command="{Binding Path=DispatcherCommand}">
<Button.CommandParameter>
<local:CurrentCommandParameters Command="{Binding Path=FirstCapability}"
Parameter="string param"/>
</Button.CommandParameter>Use first capability</Button>
, где
// DispatcherCommand parameter class
public class DispatcherCommandParameters : DependencyObject
{
// target async command
public IAsyncCommand Command
{
set { SetValue(CommandProperty, value); }
get { return (IAsyncCommand)GetValue(CommandProperty); }
}
// its parameter
public object Parameter
{
set { SetValue(ParameterProperty, value); }
get { return GetValue(ParameterProperty); }
}
public static readonly DependencyProperty CommandProperty;
public static readonly DependencyProperty ParameterProperty;
static CurrentCommandParameters()
{
CommandProperty = DependencyProperty.Register("Command",
typeof(IAsyncCommand),
typeof(CurrentCommandParameters),
new PropertyMetadata());
ParameterProperty = DependencyProperty.Register("Parameter",
typeof(object),
typeof(CurrentCommandParameters),
new PropertyMetadata());
}
}
но это не работает. DispatcherCommand.Execute (параметр объекта) получает экземпляр класса DispatcherCommandParameters, но его свойство Command имеет значение null.
Что можно сделать в этой ситуации?
В конструкторе окна успешно создана та же привязка, что и в xaml: Ошибка:
<Button Name="StupidButton" Command="{Binding Path=DispatcherCommand}">
...
public MainWindow()
{
InitializeComponent();
// set up data context
AsyncModel model = new AsyncModel();
this.DataContext = model;
// set up binding
DispatcherCommandParameters dcp = new DispatcherCommandParameters();
dcp.Parameter = "string parameter value set in code";
Binding myBinding = new Binding("FirstCapability");
myBinding.Source = model;
BindingExpressionBase be = BindingOperations.SetBinding(dcp,
DispatcherCommandParameters.CommandProperty, myBinding);
StupidButton.CommandParameter = dcp;
// now when "StupidButton" is pressed,
// DispatcherCommand.Execute(object parameter)
// receives correct reference to AsyncModel.FirstCapability command in
// ((DispatcherCommandParameters)parameter).Command property
}