2

WPF (XAML) を使用してウィンドウのオプションを変更するたびに、Resfresh() または Work() メソッドを呼び出す方法を理解しようとしています。すでに質問していますが、十分に明確ではありませんでした。ですから、より良い例でもう一度質問します。

多くのビジュアル コンポーネントからラベルを更新する方法を知りたいです。0 から 9 までのラベルが付いた 10 個のチェックボックスがあり、チェックされている場合はそれらの合計を計算したいとします。

従来の Winform では、イベント ハンドラー OnClick() を作成し、CheckBox の状態が変化するたびにイベントを呼び出します。OnClick は Refresh() グローバル メソッドを呼び出します。Refresh は、各 CheckBox がチェックされているかどうかを評価し、必要に応じてそれらを合計します。Refresh() メソッドの最後で、Label Text プロパティを合計に設定します。

XAML とデータ バインディングを使用してそれを行うにはどうすればよいですか?

<CheckBox Content="0" Name="checkBox0" ... IsChecked="{Binding Number0}" />
<CheckBox Content="1" Name="checkBox1" ... IsChecked="{Binding Number1}" />
<CheckBox Content="2" Name="checkBox2" ... IsChecked="{Binding Number2}" />
<CheckBox Content="3" Name="checkBox3" ... IsChecked="{Binding Number3}" />
<CheckBox Content="4" Name="checkBox4" ... IsChecked="{Binding Number4}" />
...
<Label Name="label1" ... Content="{Binding Sum}"/>

私のViewModelには、チェックボックスごとにデータバインドされたプロパティがあり、合計用に1つあります

private bool number0;
public bool Number0
{
    get { return number0; }
    set
    {
        number0 = value;
        NotifyPropertyChanged("Number0");
        // Should I notify something else here or call a refresh method?
        // I would like to create something like a global NotifyPropertyChanged("Number")
        // But how can I handle "Number" ???
    }
}

// Same for numer 1 to 9 ...

private bool sum;
public bool Sum
{
    get { return sum; }
    set
    {
        sum = value;
        NotifyPropertyChanged("Sum");
    }
}

private void Refresh() // or Work()
{ 
    int result = 0;
    if (Number0)
        result = result + 0; // Could be more complex that just addition
    if (Number1)
        result = result + 1; // Could be more complex that just addition
    // Same until 9 ...
    Sum = result.ToString(); 
}

私の質問は、この Refresh メソッドをいつどのように呼び出す必要があるかです。

4

3 に答える 3

1

次のようなものを試してください-

private bool number0;
    public bool Number0
    {
        get { return number0; }
        set
        {
            number0 = value;
            NotifyPropertyChanged("Number0");
            NotifyPropertyChanged("Sum");
        }
    }

    public bool Sum
    {
        get { return this.EvaluateSum(); }
    }

    private bool EvaluateSum() 
    {
        int result = 0; 
        if (Number0) 
            result = result + 0; // Could be more complex that just addition 
        if (Number1) 
            result = result + 1; // Could be more complex that just addition 
        // Same until 9 ... 

        return result.ToString(); 
    }

注: これはテストされていません。

上記が気に入らない場合は、次の変更を行うことができます。

新しいクラスを宣言する

public class SomeClass: INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    private bool number0;
    public bool Number0
    {
        get { return number0; }
        set
        {
            number0 = value;
            this.NotifyPropertyChanged("Number0");
        }
    }

    private bool sum;
    public bool Sum
    {
        get { return sum; }
        set
        {
            sum = value;
            this.NotifyPropertyChanged("Sum");
        }
    }

    protected void NotifyPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
        if ((propertyChanged != null))
        {
            propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
        }
    }
}

注: それに応じてバインディングを変更します

SomeClass のプロパティ変更時:

void SomeClass_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName.Contains("Number"))
        {
            (sender as SomeClass).Sum = EvaluateSum(); // put or call the sum logic
        }
    }
于 2012-07-18T08:51:09.967 に答える
1

あなたのデザインにはいくつかの間違いがあります。これが私がすることです:

を持つ代わりにNumber0...9BindingList<bool> Numbers

次に、XAML で、次のようにチェックボックスを表示します。

<ItemsControl ItemsSource="{Binding Numbers}">
   <ItemsControl.ItemTemplate>
      <DataTemplate>
         <CheckBox IsChecked="{Binding} Content="Name the checkbox here" />
      </DataTemplate>
   </ItemsControl.ItemTemplate>
</ItemsControl>

<Label Content="{Binding Numbers, Converter={StaticResource NumbersToSumConverter}}" />

次のようNumbersToSumConverterIValueConverter

public NumbersToSumConverter : IValueConverter
{
   public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
   {
      var numbers = value as BindingList<bool>();
      //Do your sum here.
   }

   public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
   {
      throw new NotImplementedException();
   }
}

これは、MVVM で行われる方法の例です。bool に単なる bool 以外を格納する必要がある場合は、BindingList<T>
実装する新しいクラスを作成し、必要な数のプロパティを追加します (セッターで発生INotifyPropertyChangedさせるようにしてください)。 次に、それをあなたのタイプとして使用します。PropertyChanged
BindingList<T>

お役に立てれば、

バブ。

于 2012-07-18T09:04:38.860 に答える
0

個人的にはRefresh()、あなたが提案するように、各 Number セッターを呼び出すだけです。

私はPropertyChanged、他のプロパティのセッター内で通知を直接発生させることに熱心ではありません。プロパティの 1 つが変更された結果、他のプロパティが変更された場合、将来どうなりNumber*ますか? すべてのセッターを調べてPropertyChanged、そのプロパティのイベントも発生させる必要があります。これは、単一責任の原則に反します。Number*セッターはプロパティを設定するためにあり、他のプロパティの変更の結果について心配する必要はありません。

専用Refresh()関数を使用すると、その関数は他のプロパティの更新を処理し、通常どおり独自の変更イベントを発生させます。

はい、Refresh()セッターを呼び出すことは素晴らしいことではありませんが、それを行うための「適切な」方法は、ビューモデルが独自のイベントをサブスクライブし、イベント ハンドラーPropertyChangedを呼び出すことです。Refresh()これにより、IMO が不要に複雑になりRefresh()、各セッターでの呼び出しは事実上同じロジックになります。

于 2012-07-18T12:24:54.077 に答える