コントロールの VisualStateManager 状態をビューモデルのプロパティにバインドするにはどうすればよいですか? それはできますか?
5 に答える
実際にできます。トリックは、Attached プロパティを作成し、実際に呼び出すプロパティ変更コールバックを追加すること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 にバインドしているため、コンバーターまたは通常実行できるその他すべてを適用できるため、viewmodel は、実際に視覚的な状態名 State を設定していることを認識する必要はありません。ブール値または列挙型などの可能性があります。
.net 3.5 で wpftoolkit を使用してこのアプローチを使用することもできますが、 の代わりににキャストtarget
する必要があります。Control
FrameworkElement
視覚状態に関するもう 1 つの簡単な注意事項として、何をしているのかわからない限り、組み込みの状態と競合するような名前を視覚状態に付けないようにしてください。これは特に検証に当てはまります。検証エンジンは、バインディングが更新されるたびに (およびその他の場合にも) 状態を設定しようとするからです。さまざまなコントロールの表示状態名のリファレンスについては、こちらを参照してください。
私は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>
ViewModel コード
// Update property as usual
private string _state;
public string State
{
get { return _state; }
set
{
_state = value;
NotifyPropertyChanged("State");
}
}
ここで、ExampleViewModel の State プロパティを設定すると、ビューで対応する状態の変更がトリガーされます。表示状態が State プロパティ値に対応する名前を持っていることを確認するか、列挙型、コンバーターなどで複雑にします。
次の記事をお読みください: Silverlight 4: VisualStateManager を使用した MVVM による状態アニメーション
または、2 つの状態を切り替えた直後であれば、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などのフレームワークを使用すると、これがさらに簡単になります。
VisualStateManager
WPFでの状態の MVVM サポートに使用するクラスを次に示します。
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}">
...