Связывание состояния представления [VisualStateManager] с моделью представления MVVM? - PullRequest
30 голосов
/ 14 мая 2011

Как связать состояние элемента управления VisualStateManager со свойством в вашей модели представления? Можно ли это сделать?

Ответы [ 4 ]

30 голосов
/ 14 мая 2011

На самом деле вы можете.Хитрость заключается в том, чтобы создать Присоединенное свойство и добавить свойство, измененное обратным вызовом, которое фактически вызывает GoToState:

public class StateHelper {
    public static readonly DependencyProperty StateProperty = DependencyProperty.RegisterAttached( 
        "State", 
        typeof( String ), 
        typeof( StateHelper ),
        new UIPropertyMetadata( null, StateChanged ) );

      internal static void StateChanged( DependencyObject target, DependencyPropertyChangedEventArgs args ) {
      if( args.NewValue != null )
        VisualStateManager.GoToState( ( FrameworkElement )target, args.NewValue, true );
    }
  }

. Затем вы можете установить это свойство в xaml и добавить привязку кВаша модель представления, как и любая другая:

<Window .. xmlns:local="clr-namespace:mynamespace" ..>
    <TextBox Text="{Binding Path=Name, Mode=TwoWay}"
             local:StateHelper.State="{Binding Path=State, Mode=TwoWay}" />
</Window>

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

Поскольку мы используем обычную привязку для привязки к Status, мы можем применять преобразователи или что-либо еще, чтокак правило, мы можем это сделать, поэтому модели представления не нужно знать, что она фактически задает имя визуального состояния, State может быть как bool или enum или как угодно.

Вы также можете использовать этоПодход с использованием wpftoolkit на .net 3.5, но вы должны привести target к Control вместо FrameworkElement.

Еще одно быстрое замечание о визуальных состояниях, убедитесь, что вы не называете свойвизуальные состояния, так что они конфликтуют со встроенными, если вы не знаете, что делаете.Это особенно верно для проверки, так как механизм проверки будет пытаться устанавливать свои состояния каждый раз, когда привязка обновляется (и в некоторых других случаях также). Перейдите сюда для ознакомления с именами визуальных состояний для различных элементов управления.

27 голосов
/ 24 августа 2012

Я новичок в WPF, но после странного скручивания состояний через слои MVVM в течение некоторого времени я, наконец, нашел решение, которое меня устраивает. Измените состояние как часть логики ViewModel и прослушайте его в представлении XAML. Нет необходимости в конвертерах или коде, стоящем за «мостовыми» методами или подобными.

Просмотр кода за конструктором

// Set ViewModel as the views DataContext
public ExampleView(ExampleViewModel vm)
{
  InitializeComponent();
  DataContext = vm;
}

Пространства имен XAML

// Reference expression namespaces
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"

Привязки XAML

// Bind GoToStateAction directly to a ViewModel property
<i:Interaction.Triggers>
  <ei:DataTrigger Binding="{Binding State}" Value="{Binding State}">
    <ei:GoToStateAction StateName="{Binding State}" />
  </ei:DataTrigger>
</i:Interaction.Triggers>

Код модели представления

// Update property as usual
private string _state;
public string State
{
  get { return _state; }
  set
  {
    _state = value;
    NotifyPropertyChanged("State");
  }
}

Теперь установка свойства State для ExampleViewModel вызовет соответствующее изменение состояния в представлении. Убедитесь, что визуальные состояния имеют имена, соответствующие значениям свойств State, или усложните их перечислениями, преобразователями и т. Д.

11 голосов
/ 16 мая 2011

Прочитайте эту статью: Silverlight 4: использование VisualStateManager для анимации состояний с MVVM

В качестве альтернативы, если вы только что переключаетесь между двумя состояниями, вы можете использовать DataStateBehaviour .Я использовал это для переключения фона при отображении страницы входа.

Пространства имен

xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" 
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 

XAML

<i:Interaction.Behaviors>
   <ei:DataStateBehavior TrueState="LoginPage" FalseState="DefaultPage" 
                         Binding="{Binding IsLoginPage}" Value="true" />
</i:Interaction.Behaviors>

Это делается еще проще благодаря использованию таких структур, как Caliburn.Micro .

1 голос
/ 07 июня 2016

Вот класс, который я использую для поддержки MVVM VisualStateManager состояний в WPF:

public static class MvvmVisualState
{
    public static readonly DependencyProperty CurrentStateProperty
        = DependencyProperty.RegisterAttached(
            "CurrentState",
            typeof(string),
            typeof(MvvmVisualState),
            new PropertyMetadata(OnCurrentStateChanged));

    public static string GetCurrentState(DependencyObject obj)
    {
        return (string)obj.GetValue(CurrentStateProperty);
    }

    public static void SetCurrentState(DependencyObject obj, string value)
    {
        obj.SetValue(CurrentStateProperty, value);
    }

    private static void OnCurrentStateChanged(object sender, DependencyPropertyChangedEventArgs args)
    {
        var e = sender as FrameworkElement;

        if (e == null)
            throw new Exception($"CurrentState is only supported on {nameof(FrameworkElement)}.");

        VisualStateManager.GoToElementState(e, (string)args.NewValue, useTransitions: true);
    }
}

В вашем XAML:

<TargetElement utils:MvvmVisualState.CurrentState="{Binding VisualStateName}">
    ...
...