Всплывание RoutedEvent или RoutedCommand в ViewModel

У меня есть коллекция ViewModels, которые отображаются как вкладки с использованием стиля для извлечения соответствующего содержимого для отображения на вкладке:

public class TabViewModel : DependencyObject
{
      public object Content
      {
          get { return (object)GetValue(ContentProperty); }
          set
          {
              SetValue(ContentProperty, value);
          }
      }

}

Вот TabControl:

<TabControl 
     ItemsSource={Binding MyCollectionOfTabViewModels}" 
     ItemContainerStyle="{StaticResource TabItemStyle}" />

А вот и стиль

<Style TargetType="TabItem" x:Key="TabItemStyle">
     <Setter Property="Content" Value="{Binding Content}"/>
</Style>

Мы создаем экземпляр пользовательского элемента управления и устанавливаем для него свойство Content модели TabViewModel, чтобы пользовательский элемент управления отображался в области содержимого TabItem.

MyCollectionOfViewModels.Add(new TabViewModel() 
{ 
     Content = new MyUserControl();
});

У меня вопрос: Я хотел бы разрешить MyUserControl (или любому из его подэлементов управления), добавленному к свойству Content TabViewModel, разрешить вызывать событие, которое обрабатывает TabViewModel.

Кто-нибудь знает, как бы я это сделал?

Мы экспериментировали с RoutedEvents и RoutedCommands, но не смогли заставить что-либо работать на 100 % и обеспечить совместимость с MVVM. Я действительно думаю, что это можно сделать с помощью RoutedEvent или RoutedCommand, но, похоже, я не могу заставить это работать.

Примечание. Я удалил часть соответствующего кода, относящегося к Prism, но если вам интересно, почему мы делаем что-то настолько глупое, то это потому, что мы пытаемся оставаться независимыми от управления с помощью Prism RegionManager.


person Anderson Imes    schedule 13.08.2009    source источник


Ответы (3)


Вы можете добавить свойство State в свой TabViewModel и проверить события DependencyPropertyChanged.

Итак, представьте следующее перечисление:

public enum TabViewModelState
{
    True,
    False,
    FileNotFound
}

Затем добавьте свойство State в TabViewModel этого перечисления:

public static readonly DependencyProperty StateProperty =
    DependencyProperty.Register("State", typeof(TabViewModelState), typeof(TabViewModel), new PropertyMetadata(OnStateChanged));

private static void OnStateChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
    TabViewModel viewModel= (TabViewModel)obj;

    //Do stuff with your viewModel
}

Используйте двустороннюю привязку к этому свойству в своем элементе управления:

<CheckBox Checked="{Binding Path=State, Converter={StaticResource StateToBooleanConverter}, Mode=TwoWay}" />

И наконец, что не менее важно, реализуйте преобразователь, который будет преобразовывать в и из исходного значения, необходимого для элемента управления.. (в моем примере логическое значение ‹--> TabViewModelState):

public class StateToBooleanConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        TabViewModelState state = (TabViewModelState) value;
        return state == TabViewModelState.True;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        bool result = (bool) value;
        return result ? TabViewModelState.True : TabViewModelState.False;
    }
}

Итак, теперь у вас есть свойство State, которое управляется пользовательским интерфейсом и выдает измененные события, когда вам нужно ответить.

Надеюсь это поможет!

person Arcturus    schedule 17.08.2009
comment
Это довольно близко к тому, что я ищу. Спасибо! - person Anderson Imes; 23.08.2009

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

Если бы у вас была команда делегата «GoCommand» в вашей ViewModel, ваша привязка кнопки UserControls выглядела бы так:

<Button Command="{Binding GoCommand}" >Go</Button>

Я проделал тот же мыслительный процесс, думая, что UserControl должен выводить команду, но это не так - привязка просто подключится, когда найдет команду в ViewModel.

Надеюсь, это поможет, и я не упустил момент! ;)

person Andy Clarke    schedule 13.08.2009
comment
Это было не совсем то, что я искал, но, вероятно, потому, что я не добавил достаточно деталей. Я немного изменил вопрос. - person Anderson Imes; 14.08.2009
comment
Надеюсь, это понятнее... Мне нужно обработать событие/команду в TabViewModel, а не в модели представления для MyUserControl. Я понимаю, что могу добавить команду в MyUserControlViewModel, но я этого не хочу. Я хочу выполнить некоторый код в MyUserControlViewModel, который обрабатывается в TabViewModel. - person Anderson Imes; 14.08.2009