2

我试图了解每次使用 WPF (XAML) 修改窗口上的选项时如何调用 Resfresh() 或 Work() 方法。我已经问了这个问题,但我还不够清楚。所以我会用一个更好的例子再问一次。

我想知道如何从许多视觉组件中更新标签。假设我们有 10 个标签为 0 到 9 的复选框,如果它们被选中,我想做它们的总和。

在经典 Winform 中,我将创建一个事件处理程序 OnClick() 并在每个 CheckBox 状态更改时调用该事件。OnClick 调用 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 中,每个复选框都有一个数据绑定属性,Sum 有一个属性

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

你的设计中有几处错误。这是我要做的:

而不是拥有Number0...9,做一个BindingList<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}}" />

作为NumbersToSumConverter一个IValueConverter,例如:

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 BindingList<T>
创建一个实现的新类INotifyPropertyChanged,并根据需要添加任意数量的属性(确保PropertyChanged在它们的 setter 中引发)。
然后将其用作您的BindingList<T>.

希望这可以帮助,

呸。

于 2012-07-18T09:04:38.860 回答
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));
        }
    }
}

注意:相应更改Binding

关于 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 回答
0

就个人而言,我会Refresh()按照您的建议调用每个数字设置器。

我不热衷于直接PropertyChanged在其他属性的设置器中发出通知。如果某些其他属性由于其中一个属性的更改而发生更改,将来会发生什么Number*?您还必须遍历每个 setter 并PropertyChanged为该属性引发事件。这违背了单一责任原则Number*setter 是用来设置属性的,不用担心其他属性改变的结果。

使用专用Refresh()函数,该函数负责更新其他属性,并且它们会像往常一样引发自己的更改事件。

是的,调用Refresh()setter 并不好,但“正确”的做法是让您的视图模型订阅自己的PropertyChanged事件并调用Refresh()事件处理程序。这增加了不必要的复杂性 IMO,并且Refresh()在每个 setter 中调用实际上是相同的逻辑。

于 2012-07-18T12:24:54.077 回答