Прежде всего извините за мой "пиджин" английский, :(
Приложение построено по шаблону MVVM. ViewModel раскрывает свою функциональность через команды и имеет специальную команду - DispatchCommand, которая получает (в параметре команды) пару других команд/параметров и выполняет полученную команду с полученным параметром. Особенностью (довольно неважной для темы) является то, что 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
}