wake-up-neo.com

[VisualStateManager] -Ansichtsstatus an ein MVVM-Ansichtsmodell binden?

Wie binden Sie den VisualStateManager-Status eines Steuerelements an eine Eigenschaft in Ihrem Ansichtsmodell? Kann es gemacht werden?

30
aL3891

Eigentlich kannst du. Der Trick besteht darin, eine angehängte Eigenschaft zu erstellen und einen Rückruf mit geänderter Eigenschaft hinzuzufügen, der tatsächlich GoToState aufruft:

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 );
    }
  }

Sie können diese Eigenschaft dann in Ihrem xaml festlegen und Ihrem Ansichtsmodell wie jeder andere eine Bindung hinzufügen:

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

Name und State sind reguläre Eigenschaften im Ansichtsmodell. Wenn Name im Ansichtsmodell entweder durch die Bindung oder etwas anderes festgelegt ist, kann es die State ändern, wodurch der visuelle Status aktualisiert wird. State kann auch durch einen anderen Faktor festgelegt werden und aktualisiert trotzdem den Ansichtsstatus im Textfeld.

Da wir eine normale Bindung zum Binden an Status verwenden, können wir Konverter oder alles andere anwenden, was wir normalerweise tun könnten, sodass das Ansichtsmodell nicht wissen muss, dass es tatsächlich einen visuellen Statusnamen, State, festlegt könnte ein Narr oder eine Aufzählung oder was auch immer sein.

Sie können diesen Ansatz auch mit dem wpftoolkit unter .net 3.5 verwenden, aber Sie müssen target in eine Control anstelle einer FrameworkElement umwandeln.

Ein weiterer kurzer Hinweis zu visuellen Zuständen: Vergewissern Sie sich, dass Sie Ihre visuellen Zustände nicht so benennen, dass sie mit den eingebauten in Konflikt stehen, es sei denn, Sie wissen, was Sie tun. Dies gilt insbesondere für die Validierung, da die Validierungsengine versucht, ihren Status jedes Mal, wenn die Bindung aktualisiert wird (und auch zu anderen Zeiten) festzulegen. Hier klicken für eine Referenz zu visuellen Statusnamen für verschiedene Steuerelemente.

29
aL3891

Ich bin neu in WPF, aber nachdem ich für einige Zeit Zustände durch MVVM-Ebenen auf merkwürdige Weise gedreht habe, habe ich endlich eine Lösung gefunden, mit der ich zufrieden bin. Ändern Sie den Status als Teil der ViewModel-Logik und hören Sie ihn in der XAML-Ansicht ab. Keine Notwendigkeit für Konverter oder Code hinter "Überbrückungsmethoden" oder dergleichen.

Code hinter Konstruktor anzeigen

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

XAML-Namespaces

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

XAML-Bindungen

// 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>

ViewModel Code

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

Wenn Sie nun die State-Eigenschaft von ExampleViewModel festlegen, wird eine entsprechende Statusänderung in der Ansicht ausgelöst. Stellen Sie sicher, dass die visuellen Zustände Namen haben, die den Zustandseigenschaftswerten entsprechen, oder komplizieren Sie sie mit Aufzählungen, Konvertern usw.

27
Olav

Lesen Sie diesen Artikel: Silverlight 4: Verwenden des VisualStateManager für Statusanimationen mit MVVM

Alternativ können Sie DataStateBehaviour verwenden, wenn Sie gerade zwischen zwei Zuständen gewechselt haben. Ich habe dies verwendet, um den Hintergrund zu wechseln, wenn die Anmeldeseite angezeigt wird.

Namespaces

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>

Dies wird durch die Verwendung eines Frameworks wie Caliburn.Micro noch einfacher.

10
Town

Hier ist eine Klasse, die ich für die MVVM-Unterstützung von VisualStateManager-Zuständen in WPF verwende:

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);
    }
}

In Ihrer XAML:

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