Изменение кистей на основе свойства ViewModel

У меня есть приложение, в котором есть CarViewModel + view (UserControl). Чего я хочу добиться, так это изменить стиль кистей при изменении связанного DataContext Car.Status.

Я узнал, как менять кисти (в коде за представлением):

private void LoadThemeResources(bool isPrepareMode)
{
    if (isPrepareMode)  
    {
        Uri themeUri = new Uri(@"/../Resources/MyBrushes.Light.xaml", UriKind.Relative);
        ResourceDictionary themeDictionary = Application.LoadComponent(themeUri) as ResourceDictionary;
        this.Resources.MergedDictionaries.Add(themeDictionary);
    }
    else
    {
        this.Resources.MergedDictionaries.Clear();
    }
}

По умолчанию приложение и все остальное имеет темную тему, распределенную по нескольким файлам. Этот MyBrushes.Light перезаписывает некоторые из них.

Но я понятия не имею, как я могу выполнить функцию LoadThemeResources на основе изменения свойства в ViewModel удобным для MVVM способом.

Я могу сделать в коде представления:

var vm = (CarViewModel) DataContext;
vm.Car.PropertyChanged += HandleStatusChanged;

Но это тесная связь между View и ViewModel.

Я также могу сделать это через Messenger (из MVVM Light), но это транслируется по всему приложению и кажется излишним.

Есть ли другой способ? Или предпочтительный способ?


person RvdK    schedule 09.10.2015    source источник


Ответы (2)


Я бы подготовил некоторое прикрепленное свойство (используемое на UserControl). Привяжите это свойство к своей модели представления и добавьте логику кода LoadThemeResources в обратном вызове измененного свойства, примерно так:

public static class ThemeService {
    public static DependencyProperty IsPrepareModeProperty = 
                  DependencyProperty.RegisterAttached("IsPrepareMode", typeof(bool), typeof(ThemeService), 
                  new PropertyMetadata(isPrepareModeChanged));
    public static bool GetIsPrepareMode(UserControl e){
       return (bool) e.GetValue(IsPrepareModeProperty);
    }
    public static void SetIsPrepareMode(UserControl e, bool value){
       e.SetValue(IsPrepareModeProperty, value);
    }
    static void isPrepareModeChanged(object sender, DependencyPropertyChangedEventArgs e){
       var u = sender as UserControl;
       u.LoadThemeResources((bool)e.NewValue);
    }        
}
//you need some public method of LoadThemeResources
public void LoadThemeResources(bool isPrepareMode) {
     //...
}

Использование в XAML:

<UserControl ...
             local:ThemeService.IsPrepareMode="{Binding Car.Status}">
      <!-- ... -->
</UserControl>

Вы также можете объявить обычный DependencyProperty для класса вашего UserControl и использовать его вместо прикрепленного свойства (использование точно такое же).

person King King    schedule 09.10.2015
comment
Спасибо, это работает! Действительно ли необходимо использовать отдельный класс вместо того, чтобы делать это непосредственно в коде UserControl? Я получаю некоторые ошибки, пытаясь сделать это: свойство зависимости в самом пользовательском контроле"> stackoverflow.com/questions/33076560/ - person RvdK; 12.10.2015
comment
@RvdK Я считаю, что вы можете это сделать, но в вашем коде из этого вопроса вы на самом деле понимаете Status как присоединенное свойство, но это, конечно, не так, попробуйте заменить views:CarView.Status просто Status. - person King King; 12.10.2015
comment
Если я это сделаю, это выдаст ошибки. Свойство «Статус» не найдено в типе «UserControl». - person RvdK; 12.10.2015
comment
@RvdK да, это правильно. Он ищет это свойство в UserControl, вы также можете попробовать изменить тег вместо UserControl, использовать свое собственное имя пользовательского элемента управления, не забудьте использовать пространство имен префикса, определенное внутри вашего UserControl, например: <local:CustomUserControl .... xmlns:local="...">... - person King King; 12.10.2015

Вы можете привязаться к свойству в своей ViewModel и использовать IValueConverter в своем представлении, чтобы превратить это свойство (будь то логическое значение, перечисление состояния и т. д.) в кисть для использования.

То есть загрузите тему/ресурсы в преобразователь (преднамеренный мост между View и ViewModel), чтобы ваш View получил нужную кисть, а ваша ViewModel должна была предоставить только «важную» информацию (биты, которые помогают решить, какую кисть использовать). нагрузка). Вся логика принятия решения находится в преобразователе.

person pete the pagan-gerbil    schedule 09.10.2015
comment
Вы имеете в виду чистое решение XAML? У вас есть пример кода, как это будет выглядеть? - person RvdK; 09.10.2015
comment
Я думаю, что немного неправильно вас понял - что вы пытаетесь сделать? Почему вы загружаете все лекарство на основе одного логического значения? - person pete the pagan-gerbil; 09.10.2015
comment
Я пытаюсь стилизовать UserControl (и внутренние UserControls). Потребуется замена большого количества щеток. Эти кисти используются в Car UserControl и дочерних элементах. - person RvdK; 10.10.2015
comment
Преобразователь предпочтительнее изменения ресурса, если вы основываете преобразователь на перечислении значений, тогда вы можете обеспечить параметры цвета для всех значений Staus. - person kidshaw; 10.10.2015