WPF数据绑定,可观察到要标记的集合

WPF数据绑定,可观察到要标记的集合,wpf,xaml,data-binding,Wpf,Xaml,Data Binding,我有一个ObservableCollection,我需要绑定到2个标签,首先显示集合中项目的数量,其次显示值的总和 第一个标签绑定到collections count属性,第二个标签直接绑定到ObservableCollection,使用转换器计算所有项的总数 XAML看起来像这样 <Grid> <ListBox Name="itemList" ItemsSource="{Binding DataList}"/> <Label Name="lblco

我有一个ObservableCollection,我需要绑定到2个标签,首先显示集合中项目的数量,其次显示值的总和

第一个标签绑定到collections count属性,第二个标签直接绑定到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>
    ObservableCollection<int> data = new ObservableCollection<int>();

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

我的虚拟机有这样一个集合

<Grid>
    <ListBox Name="itemList" ItemsSource="{Binding DataList}"/>
    <Label Name="lblcount" Content="{Binding DataList.Count}" />
    <Label Name="lblTotal" Content="{Binding DataList, Converter={StaticResource calculateTotalConvertor}" />
</Grid>
    ObservableCollection<int> data = new ObservableCollection<int>();

    public ObservableCollection<int> DataList
    {
        get { return data; }
        set { data = value; }
    }
ObservableCollection数据=新的ObservableCollection();
公共可观察收集数据列表
{
获取{返回数据;}
设置{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();
    }
}
公共类CalculateTotalConverter:IValueConverter
{
公共对象转换(对象值、类型targetType、对象参数、CultureInfo区域性)
{
ObservableCollection集合=作为ObservableCollection的值;
return collection.Sum();
}
公共对象转换回(对象值、类型targetType、对象参数、CultureInfo区域性)
{
抛出新的NotImplementedException();
}
}
问题是在DataList、ListView和显示项目计数的标签中添加新项目时得到更新,但“lblTotal”并没有得到总计数的更新

基本上,如何强制您的绑定根据可观察的收集更改进行评估?它如何直接用于ListView或DataGrid,而不用于label

我知道这个问题可以通过在VM中创建一个属性来解决,在集合更新时显示total并引发属性更改,但有比这更好的解决方案吗


当然,这是我实际问题的简化形式,我没有访问ViewModel和集合的权限,它是第三方控件。我正在创建一个包装器用户控件,并与视图有一个相对绑定到它的内部集合。

它没有更新,因为它绑定到
DataList
DataList
没有更改,计数标签更新,因为它绑定到
DataList.count
,当一个项目添加到列表中时更新

我能想到的更新
Sum
标签的唯一方法是通知用户界面
DataList
已更改,但这将导致列表框重新绑定列表,其性能将比仅在模型上使用属性更新
Sum
要昂贵得多


因此,我认为最好的选择是在模型上使用一个属性,使用
可观察集合
集合更改开发
或在将项目添加到列表的逻辑中计算总和
ListView
DataGrid
,因为这些是侦听
ObservableCollection
CollectionChangedEvent
项控件,当通过添加或删除项更改集合本身时,会引发该控件

另一方面,
标签是一个
ContentControl
,它只侦听
属性changedevent
。由于数据列表在插入后与插入前相同,因此不会引发任何事件

刚刚看到您的编辑:

如果要创建包装控件,请为第三方控件指定名称,并从控件的代码隐藏连接到其内部集合的
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));
    }
}
public分部类主窗口:窗口,INotifyPropertyChanged
{
ObservableCollection_list=新的ObservableCollection();
int _sum=0;
随机rnd=新随机();
公共主窗口()
{
DataList=新的ObservableCollection();
DataList.CollectionChanged+=新系统.Collections.Specialized.NotifyCollectionChangedEventHandler(DataList\u CollectionChanged);
DataContext=this;
初始化组件();
}
无效数据列表\u CollectionChanged(对象发送方,System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
开关(电动)
{
案例NotifyCollectionChangedAction。添加:
foreach(e.NewItems中的对象编号)
_总和+=(整数)个数;
打破
案例NotifyCollectionChangedAction。删除:
foreach(e.OldItems中的对象编号)
_总和-=(整数)个数;
打破
}
OnNotifyPropertyChanged(“金额”);
}
公共整数和{get{return_Sum;}}
公共ObservableCollection数据列表{get;set;}
私有无效添加\u Btn\u单击(对象发送者,路由目标)
{
DataList.Add(rnd.Next(0256));
}
私有无效删除\u Btn\u单击(对象发送方,路由目标)
{
如果(DataList.Count==0)
返回;
DataList.RemoveAt(DataList.Count-1);
}
公共事件属性更改事件处理程序属性更改;
void OnNotifyPropertyChanged(字符串属性)
{
if(PropertyChanged==null)
返回;
PropertyChanged(此,新PropertyChangedEventArgs(property));
}
}

其他答案正确地解释了它不更新的原因。要强制更新,您可以将转换器更改为
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();
    }
}

现在,第二个绑定将通知在添加或删除项时绑定需要更新,但您可以忽略计数值而不使用它。

您是否尝试过
set{data=value;RaisePropertyChanged(“data”);}
?老实说,我将提供一个完全符合您需要的属性,并在VM中处理逻辑。使用转换器是一件很奇怪的事情,我尽量避免使用它。想想看,一个转换应该把一个值转换成另一个值,你正在把一个列表转换成一个数字。会议