web-dev-qa-db-ja.com

ビューモデルのプロパティへの双方向バインドビューのDependencyProperty?

ネット上の複数のソースから、MVVMでは、ビューとビューモデルの間の通信/同期は依存関係プロパティを介して行われる必要があることがわかります。私がこれを正しく理解している場合、双方向バインディングを使用して、ビューの依存関係プロパティをビューモデルのプロパティにバインドする必要があります。現在、以前に同様の質問が行われていますが、十分な回答はありません。

このかなり複雑な問題の分析を始める前に、私の質問を次に示します。

customビューのDependencyPropertyをビューモデルのプロパティと同期するにはどうすればよいですか?

理想的な世界では、次のようにバインドするだけです。

<UserControl x:Class="MyModule.MyView" MyProperty="{Binding MyProperty}">

MyPropertyUserControlのメンバーではないため、これは機能しません。どー!私はさまざまなアプローチを試しましたが、どれも成功しませんでした。

1つの解決策は、上記を機能させるために必要な依存関係プロパティを含む基本クラスUserControlExを定義することです。ただし、これはすぐに非常に複雑になります。十分じゃない!

24
l33t

ViewからViewModelを分離するためにCaliburn.Microを使用します。それでも、MVVMでは同じように機能する可能性があります。 MVVMもビューのDataContextプロパティをViewModelのインスタンスに設定すると思います。

見る

// in the class of the view: MyView
public string ViewModelString // the property which stays in sync with VM's property
{
    get { return (string)GetValue(ViewModelStringProperty); }
    set
    {
        var oldValue = (string) GetValue(ViewModelStringProperty);
        if (oldValue != value) SetValue(ViewModelStringProperty, value);
    }
}

public static readonly DependencyProperty ViewModelStringProperty =
    DependencyProperty.Register(
        "ViewModelString",
        typeof(string),
        typeof(MyView),
        new PropertyMetadata(OnStringValueChanged)
        );

private static void OnStringValueChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
    // do some custom stuff, if needed
    // if not, just pass null instead of a delegate
}    

public MyView()
{
    InitializeComponent();
    // This is the binding, which binds the property of the VM
    // to your dep. property.
    // My convention is give my property wrapper in the view the same
    // name as the property in the VM has.
    var nameOfPropertyInVm = "ViewModelString"
    var binding = new Binding(nameOfPropertyInVm) { Mode = BindingMode.TwoWay };
    this.SetBinding(SearchStringProperty, binding);
}

VM

// in the class of the ViewModel: MyViewModel
public string ViewModelStringProperty { get; set; }

この種の実装は、INotifyPropertyChangedインターフェースの実装を完全に欠いていることに注意してください。このコードを適切に更新する必要があります。

6

XAMLでそれを実行したい場合は、スタイルを使用してそれを実現してみることができます。

次に例を示します。

<UserControl x:Class="MyModule.MyView"
             xmlns:local="clr-namespace:MyModule">
    <UserControl.Resources>
        <Style TargetType="local:MyView">
            <Setter Property="MyViewProperty" Value="{Binding MyViewModelProperty, Mode=TwoWay}"/>
        </Style>
    </UserControl.Resources>
    <!-- content -->
</UserControl>

あなたの場合、MyViewPropertyMyViewModelPropertyはどちらもMyPropertyという名前になりますが、何が何であるかを明確にするために、異なる名前を使用しました。

12
Grx70

ViewでDependencyProperty "DepProp"を定義し、ViewModelでまったく同じ値を使用したいとします(INotifyPropertyChangedを実装しますが、DependencyObjectは実装しません)。 XAMLで次のことができるはずです。

<UserControl x:Class="MyModule.MyView"
         xmlns:local="clr-namespace:MyModule"
             x:Name="Parent">
    <Grid>
        <Grid.DataContext>
            <local:MyViewModel DepProp="{Binding ElementName=Parent, Path=DepProp}"/>
        </Grid.DataContext>
    ...
    </Grid>
</UserControl>
3
somebody