3

私は最初のWPF/MVVMプロジェクトに取り組んでおり、いくつかのことに頭を悩ませています。このプロジェクトは、VBですでに作成されているもののスタンドアロンアプリケーションになるため、すべてのロジックとビジネスルールがすでに存在します。

私が遭遇した問題は、バインディングを実装しようとしていることです。アプリケーションにいくつかのボタンがあり、それらのすべてのプロパティ(IsEnabled、Text、image)は列挙型に依存しています。列挙型はステータスに基づいており、モデルに存在します。

VBアプリケーションでは、ボタンのプロパティを更新するための大規模なswitchステートメントがあり、ステータスが変更される可能性のあるすべての場所で呼び出されました。したがって、このバージョンでは、ステータスに基づいてViewModelの各ボタンにブール値と文字列がありますが、ステータスが変更されるたびに(非常に頻繁に)更新するように強制する方法はありません。

INotifyPropertyChangedについて少し読みましたが、ViewModelの変更を開始するために必要なプロパティはモデルにあります。私はこれを間違った方法で行っていますか?

4

4 に答える 4

3

私はDataTriggerあなたのボタンのスタイルでを使用します。バインドされた値が更新されるたびに、DataTriggerが再評価され、必要に応じて新しい値が設定されます

<Style x:Key="MyButtonStyle" TargetType="{x:Type Button}">
    <Style.Triggers>
        <DataTrigger Binding="{Binding MyEnumProperty}" 
                     Value="{x:Static local:MyEnum.Value1}">
            <Setter Property="IsEnabled" Value="False" />
            <Setter Property="Content" Value="Value 1" />
        </DataTrigger>
        <DataTrigger Binding="{Binding MyEnumProperty}" 
                     Value="{x:Static local:MyEnum.Value2}">
            <Setter Property="IsEnabled" Value="True" />
        </DataTrigger>
    </Style.Triggers>
</Style>

あなたはあなたのImageスタイルで同じことをするでしょう-ステータス列挙型の現在の値が何であるかに基づいてにImage.Sourceプロパティを設定します。DataTrigger

MyEnumProperty値が変更されたことをUIが認識できるように、変更時にPropertyChange通知を発行し、その値に依存するバインディングを更新する必要があることに注意してください。

于 2012-10-02T15:00:57.653 に答える
1

IsEnabledそれぞれの、、、TextおよびImageプロパティをButtonビューモデルのStatusプロパティにバインドする必要があります。次に、列挙値を探している適切なブール値、文字列、または画像にIValueConverter本質的に変換する3つの実装を提供する必要があります。StatusコントロールごとButtonに、コンバーターがビューモデルのStatusプロパティと比較するために使用できる追加のパラメーターを指定します。

このようなもの:

<myView.Resources>
    <local:statToBoolConverter x:Key="statToBoolConv" />
    <local:statToTextConverter x:Key="statToTextConv" />
    <local:statToImgConverter x:Key="statToImgConv" />
</myView.Resources>

// ..... further down in code ....

<Button x:Key="aButton" 
    IsEnabled="{Binding Path=Status, Converter={StaticResource statToBoolConv}, 
        ConverterParamter=caseA}"
    Text="{Binding Path=Status, Converter={StaticResource statToTextConv}, 
        ConverterParamter=caseA}"
    Image="{Binding Path=Status, Converter={StaticResource statToImgConv},
        ConverterParamter=caseA}"/>

<Button x:Key="aButton" 
    IsEnabled="{Binding Path=Status, Converter={StaticResource statToBoolConv}, 
        ConverterParamter=caseB}"
    Text="{Binding Path=Status, Converter={StaticResource statToTextConv}, 
        ConverterParamter=caseB}"
    Image="{Binding Path=Status, Converter={StaticResource statToImgConv},
        ConverterParamter=caseB}"/>

の実装の詳細はIValueConverter非常に簡単なのでここでは説明しませんが、ここで詳細情報を入手できます(例を示します)。

http://msdn.microsoft.com/en-us/library/system.windows.data.ivalueconverter.aspx

もう1つの注意:INotifyPropertyChangedすべてのボタンのバインディング更新がトリガーされるため、1回のNotifyPropertyChanged("MyStatus")呼び出しでうまくいきます。

于 2012-10-02T13:49:41.937 に答える
1

WPFの列挙型へのバインディングをいじってみましたが、あまり好きではありませんでした。

これを回避するには、プロパティをモデル内のそれぞれのプロパティにマッピングします。getメソッドでは、列挙型の状態への依存関係を実装します。

例えば:

<Button  Height="41" HorizontalAlignment="Center" Style="{StaticResource ButtonStyle}"
                    Margin="407,77,289,0" Name="buttonSearch" VerticalAlignment="Top" Width="137" Click="search_click" 
                    IsEnabled="{Binding IsSearchButtonEnabled}" ...

この列挙型があるとしましょう:

public enum States
{
    StateOne,
    StateTwo,
    StateThree
}

ビューモデルでは、次のことができます。

    public bool IsSearchButtonEnabled
    {
        get
        {
            return ((Model.actualState) == States.StateTwo);
        }
    }

自動的に更新するには、ViewModelがINotifyPropertyChangedを実装する必要があります。私は、ViewModelsが常にサブクラス化する一般的な実装を使用して、物事を単純化します。これはこのように見え、InvokePropertyChanged(string propertyName)が呼び出されるたびにビューの更新を処理する必要があります。ViewModelは、ビューを更新する必要があること、およびこのメソッドがいつ呼び出されるかを知る必要があります。モデルで同じ手法を使用して、状態列挙型のセッターの変更をサブスクライバーVMに通知するイベントハンドラーをモデルに配置できます。

public class ViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    public static event PropertyChangedEventHandler PropertyChangedStatic;

    public void InvokePropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }

    public static void InvokePropertyChangedStatic(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChangedStatic;
        if (handler != null) handler(null, new PropertyChangedEventArgs(propertyName));
    }
} 
于 2012-10-02T10:47:18.087 に答える
1

MVVMでは、ViewModelから直接View内の何かを参照するべきではありません。

最善の解決策は、列挙型プロパティの値に基づいてCanExecuteアクションを持つMVVM-LightRelayCommandなどのコマンドを使用することです。次に、ボタンのコマンドプロパティbindをViewModelの適​​切なコマンドプロパティにバインドします。これにより、ボタンの有効状態が自動的に設定されます。

次に、enumプロパティのsetメソッドで、コマンドごとにCanExecuteChangedイベントを呼び出します。

于 2012-10-02T13:12:36.247 に答える