4

最初にコレクション内のアイテムの数を表示し、次に値の合計を表示するために、2 つのラベルにバインドする必要がある ObservableCollection があります。

最初のラベルはコレクションの count プロパティにバインドされ、2 番目のラベルは ObservableCollection に直接バインドされ、コンバーターを使用してすべてのアイテムの合計を計算します

XAMLは次のようになります

<Grid>
    <ListBox Name="itemList" ItemsSource="{Binding DataList}"/>
    <Label Name="lblcount" Content="{Binding DataList.Count}" />
    <Label Name="lblTotal" Content="{Binding DataList, Converter={StaticResource calculateTotalConvertor}" />
</Grid>

私のVMにはこのようなコレクションがあります

    ObservableCollection<int> data = new ObservableCollection<int>();

    public ObservableCollection<int> DataList
    {
        get { return data; }
        set { data = value; }
    }

私のコンバーターコードは

public class CalculateTotalConvertor : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        ObservableCollection<int> collection = value as ObservableCollection<int>;

        return collection.Sum();
    }

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

問題は、DataList、ListView、およびアイテムの数を示すラベルに新しいアイテムを追加することですが、「lblTotal」は合計数で更新されません。

基本的に、 ObservableCollection の変更時にバインディングを強制的に評価する方法は? ListView または DataGrid では直接機能しますが、 label では機能しませんか?

この問題は、VM でプロパティを作成して合計を表示し、コレクションが更新されたときにプロパティの変更を発生させることで解決できることを知っていますが、それよりも優れた解決策はありますか?

もちろん、これは実際の問題を簡略化したものです。ViewModel とコレクション、つまりサード パーティ コントロールにアクセスすることはできません。ラッパー ユーザー コントロールを作成しており、その内部コレクションへのビューとの相対的なバインディングがあります。

4

3 に答える 3

3

他の回答は、更新されていない理由を正しく説明しています。強制的に更新するには、コンバーターを次のように変更できますIMultiValueConverter

public class CalculateTotalConvertor : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        ObservableCollection<int> collection = values.FirstOrDefault() as ObservableCollection<int>;

        return collection.Sum();
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

次に、バインディングをMultiBindingカウントもプルするに変更します。

<Label Name="lblTotal">
    <Label.Content>
        <MultiBinding Converter="{StaticResource calculateTotalConvertor}">
            <Binding Path="DataList"/>
            <Binding Path="DataList.Count"/>
        </MultiBinding>
    </Label.Content>
</Label>

2 番目のバインディングは、アイテムが追加または削除されたときにバインディングを更新する必要があることを通知しますが、カウント値を無視して使用しないようにすることができます。

于 2013-02-06T20:54:25.363 に答える
0

バインドされていて変更されていないため、更新されDataListていません。アイテムがリストに追加されるとDataList、バインドが更新されるため、カウント ラベルが更新されます。DataList.Count

ラベルを更新するために私が考えることができる唯一の方法は、変更されSumたことをUIに通知することですDataListが、これによりListBoxがリストを再バインドし、モデルの更新にプロパティを設定するよりもはるかにコストがかかりますSum。_

したがって、モデルのプロパティを使用して、ObservableCollections CollectionChangedEventまたはリストにアイテムを追加するロジックで合計を計算するのが最善の方法だと思います

于 2013-02-06T10:47:28.267 に答える
0

これらは、アイテムの追加または削除によってコレクション自体が変更されたときに発生するのをリッスンする であるため、 ListViewandに対して機能します。DataGridItemsControlObservableCollectionCollectionChangedEvent

一方LabelContentControlは のみをリッスンするPropertyChangedEventです。DataList はObservableCollection挿入後も以前と同じであるため、イベントは発生しません。

あなたの編集を見ただけです:

ラッピング コントロールを作成している場合は、サード パーティ コントロールに名前を付けてCollectionChangedEvent、コントロールのコード ビハインドから内部コレクションに接続します。そうすれば、更新通知をラッピング ビューにプッシュすることができます。

追加のプロパティを使用すると、コンバーターのコードが節約されます。コードビハインドから:

public partial class MainWindow : Window, INotifyPropertyChanged
{
    ObservableCollection<int> _list = new ObservableCollection<int>();
    int _sum = 0;
    Random rnd = new Random();

    public MainWindow()
    {
        DataList = new ObservableCollection<int>();
        DataList.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(DataList_CollectionChanged);
        DataContext = this;
        InitializeComponent();
    }

    void DataList_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        switch (e.Action)
        {
            case NotifyCollectionChangedAction.Add:
                foreach (object number in e.NewItems)
                    _sum += (int)number;
                break;
            case NotifyCollectionChangedAction.Remove:
                foreach (object number in e.OldItems)
                    _sum -= (int)number;
                break;
        }
        OnNotifyPropertyChanged("Sum");
    }

    public int Sum { get { return _sum; } }
    public ObservableCollection<int> DataList { get; set; }

    private void Add_Btn_Click(object sender, RoutedEventArgs e)
    {
        DataList.Add(rnd.Next(0, 256));
    }

    private void Remove_Btn_Click(object sender, RoutedEventArgs e)
    {
        if (DataList.Count == 0)
            return;

        DataList.RemoveAt(DataList.Count - 1);
    }

    public event PropertyChangedEventHandler PropertyChanged;

    void OnNotifyPropertyChanged(string property)
    {
        if (PropertyChanged == null)
            return;

        PropertyChanged(this, new PropertyChangedEventArgs(property));
    }
}
于 2013-02-06T11:10:49.573 に答える