Связывание команд в многооконном приложении WPF - PullRequest
3 голосов
/ 25 марта 2011

Мое приложение может иметь несколько дизайнерских окон. Каждое окно состоит из нескольких пользовательских элементов управления, которые динамически взаимодействуют с помощью RelayCommands. Я создал следующий класс в качестве основы для командной инфраструктуры.

public static class Commands
{
    public static readonly RoutedCommand EntityEditRequest = new RoutedCommand();
    public static  RelayCommand EntityEditorChangeRequest;
    public static RelayCommand XMLUpdateRequest;
    public static RelayCommand SaveRequest;   
}

Каждая модель представления для пользовательских элементов управления будет делать что-то подобное в конструкторе

 public XMLEditorViewModel()
 {
        Commands.Commands.SaveRequest = new RelayCommand(Save_Executed);
        Commands.Commands.XMLUpdateRequest = new RelayCommand(UpdateXML); 
 }

Однако я полностью упустил момент, что приложение может иметь несколько окон. Когда каждое окно открывается, статические команды устанавливаются для этого конкретного окна.

Пример:

Открыто окно A - конструкторы для пользовательских контроллеров устанавливают RelayCommands, и все в порядке.

Открыто окно B - конструкторы для пользовательских контроллеров устанавливают RelayCommands. Привязка команды окна A потеряна!

Поэтому, когда я меняю вкладку на Окно A (окна с вкладками), никакие команды не работают.

Мне нужна идея, чтобы при смене вкладки активное окно всегда задавало команды. Я могу попытаться поместить командование в событие tab_selection_changed, но мне как-то плохо. Есть ли правильный способ сделать это? Любая помощь очень ценится.

Edit:

Вопрос оказался немного запутанным среди читателей. Я не пытаюсь сделать несколько подписчиков на команду. В любой данный момент активным является только одно окно. Это окно состоит из нескольких пользовательских элементов управления, некоторые из которых загружаются динамически с помощью команд; но каждая команда обрабатывается одним классом модели представления, поэтому нет нескольких подписчиков. Моя проблема в том, что приложение может загружать несколько окон во вкладках - только одно окно активно в любой заданной точке, но пользователь может перейти на другую вкладку и сделать другое окно активным. Поскольку конструктор модели представления назначает статические RelayCommands, при загрузке каждого нового окна статическая команда устанавливается на новую привязку.

Окно. Открытое окно. Конструктор модели представления устанавливает привязку статической команды к своему обработчику команд объекта. Окно А активно. Командование в порядке.

Окно B - конструктор модели представления загруженного окна B устанавливает статическую привязку команды к своему обработчику команд объекта. Окно B активно. Командование в порядке.

Теперь пользователь выбирает вкладку Окно А, чтобы установить Окно А как активное. Командование не будет работать. Конечно, это не так, поскольку команда привязана к обработчику команд окна B.

Теоретически статические команды могут обрабатывать сценарий, поскольку в любой заданной точке будет только одно активное окно. Но как ??

Ответы [ 4 ]

2 голосов
/ 26 марта 2011

Глобальная команда должна быть CompositeCommand или аналогичным подходом (CompositeCommand от Prism).Это позволит нескольким дочерним элементам регистрироваться с помощью команды.

  public static CompositeCommand SaveCommand = new CompositeCommand();

Затем к команде можно получить доступ через модели представления или, где это применимо, примерно так ...

  SaveCommand = new DelegateCommand<object>(Save, CanExecuteSave);
  GlobalCommands.SaveCommand.RegisterCommand(SaveCommand);

Затем можно использоватьIActiveAware интерфейс , чтобы определить, какой Window является активным Window и действовать соответственно команде.

Существует также публикация MSDN на , создающая глобально доступные команды.Не забудьте отменить регистрацию команды, чтобы избежать утечки памяти.

1 голос
/ 26 марта 2011

Команды, которые не являются специфичными для вида, могут быть определены в статических классах.

Команды, которые являются специфическими для вида, должны быть либо определены в модели представления, передаваемой как DataContext для просмотра, что позволяет раздельно реализовать разные представления с разнымипросматривать модели или, по крайней мере, иметь представления, передающие CommandParameter, который можно использовать для их идентификации (например, ссылки на представление) или их DataContext.

Если команды являются статическими, зарегистрируйте их только один раз, возможно, всинглтон, используемый моделями вида.

1 голос
/ 26 марта 2011

По какой причине вы решили поместить его в статический класс?

class XMLEditorViewModel
{
    public ICommand SaveRequest { get; private set; }

    public XMLEditorViewModel()
    {
        SaveRequest = new RelayCommand(Save_Executed)?
    }
}
0 голосов
/ 27 апреля 2011

создайте глобально доступную команду, создайте экземпляр DelegateCommand или CompositeCommand и выставьте его через статический класс.

открытый статический класс GlobalCommands { public static CompositeCommand MyCompositeCommand = new CompositeCommand (); } В вашем модуле свяжите дочерние команды с общедоступной командой.

GlobalCommands.MyCompositeCommand.RegisterCommand (команда1); GlobalCommands.MyCompositeCommand.RegisterCommand (команда2); Чтобы повысить тестируемость вашего кода, вы можете использовать прокси-класс для доступа к глобально доступным командам и макетировать этот прокси-класс в своих тестах.

В следующем примере кода показано, как привязать кнопку к команде в WPF.

Выполнить мою составную команду

...