我在代码后面有一个由手动处理的ObservableCollection<T>支持的DataGrid。当我向备份列表添加新项目或删除新项目时,Count会更新,但ItemsSource不会收到通知,因此Price更新的总和。我甚至尝试过BindingList<T>,但就连Count也停止了更新!怎么回事?
XAML:
<Label>
<Label.Content>
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}Count: {0}, Sum: {1}" NotifyOnTargetUpdated="True" NotifyOnSourceUpdated="True">
<Binding ElementName="datagrid" Path="ItemsSource.Count" UpdateSourceTrigger="PropertyChanged"/>
<Binding ElementName="datagrid" Path="ItemsSource" Converter="{StaticResource SumConverter}" UpdateSourceTrigger="PropertyChanged" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</Label.Content>
</Label>SumConverter:
[ValueConversion(typeof(ObservableCollection<DocView>), typeof(String))]
public class SumConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value != null && value is ObservableCollection<DocView>)
{
ObservableCollection<DocView> items = (ObservableCollection<DocView>)value;
return items.Sum(x => x.Price);
}
else
return 0;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}代码隐藏:
ObservableCollection<DocView> list = new ObservableCollection<DocView>();
datagrid.DataContext = list;发布于 2014-07-11 23:55:12
我认为问题出在您将列表绑定到datagrid的方式上,转换器不会接收ItemSource中的更改,因为该属性不会更改。收集不会触发PropertyChanged事件。试试这个:
datagrid.ItemsSource = list;并在您的XAML中使用多绑定上的转换器。绑定到ItemsSource.Count将在集合更改时触发通知。注意:您不需要在Label中嵌入TextBlock。
<TextBlock Grid.Row="2">
<TextBlock.Text>
<MultiBinding Converter="{StaticResource SumConverter}">
<Binding ElementName="datagrid" Path="ItemsSource" />
<Binding ElementName="datagrid" Path="ItemsSource.Count"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>显然,您需要相应地修改您的转换器。
public class SumConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (values != null && values.Length > 0 && values[0] is ObservableCollection<string>)
{
ObservableCollection<DocView> items = (ObservableCollection<DocView>)values[0];
return string.Format("Count: {0}, Sum: {1}", items.Count, items.Sum(x => x.Price));
}
else
return "Count: 0, Sum: 0";
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}这是一个只需要最少更改的解决方案。最好是将集合绑定到ViewModel,而不是绑定到datagrid.ItemsSource。
发布于 2014-07-12 10:01:42
完整的解决方案:
INPC,其中BindingList<T>而不是ObservableCollection<T> (如果使用ObservableCollection<T>,则列表中现有项目的属性更新不会触发对UI的更新,而BindingList<T>支持此功能)XAML:
<DataGrid x:Name="datagrid" ItemsSource="{Binding List}" />
<Label>
<Label.Content>
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}Count: {0}, Sum: {1}" NotifyOnTargetUpdated="True" NotifyOnSourceUpdated="True">
<Binding ElementName="datagrid" Path="DataContext.Count"/>
<Binding ElementName="datagrid" Path="DataContext.Total"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</Label.Content>
</Label>代码隐藏:
DocViewModel list= new DocViewModel();
datagrid.DataContext = list;DocViewModel
public class DocViewModel : INotifyPropertyChanged
{
public DocViewModel()
{
this.list = new BindingList<DocView>();
this.list.ListChanged += list_ListChanged;
}
void list_ListChanged(object sender, ListChangedEventArgs e)
{
OnPropertyChanged("Total");
OnPropertyChanged("Count");
}
public event PropertyChangedEventHandler PropertyChanged;
private BindingList<DocView> list;
public BindingList<DocView> List
{
get { return list; }
set
{
list = value;
OnPropertyChanged("List");
}
}
public decimal Total
{
get { return list.Sum(x => x.Price); }
}
private void OnPropertyChanged(String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public int Count
{
get { return list.Count; }
}
}DocView:
public class DocView : INotifyPropertyChanged
{
private decimal price;
public decimal Price
{
get { return price; }
set
{
price = value;
OnPropertyChanged("Price");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}编辑
这里是视图模型的一个更具体的通用实现,它让你对不同的项目类型使用相同的逻辑,并提供自定义的Total和Count计算器:
public class GenericListViewModel<T> : INotifyPropertyChanged
{
Func<BindingList<T>, decimal> totalCalculator;
Func<BindingList<T>, int> countCalculator;
public GenericListViewModel(Func<BindingList<T>, decimal> _totalCalculator, Func<BindingList<T>, int> _countCalculator)
{
this.list = new BindingList<T>();
this.list.ListChanged += list_ListChanged;
this.totalCalculator = _totalCalculator;
this.countCalculator = _countCalculator;
}
void list_ListChanged(object sender, ListChangedEventArgs e)
{
OnPropertyChanged("Total");
OnPropertyChanged("Count");
}
public event PropertyChangedEventHandler PropertyChanged;
private BindingList<T> list;
public BindingList<T> List
{
get { return list; }
set
{
list = value;
OnPropertyChanged("List");
}
}
public decimal Total
{
get
{
if (totalCalculator != null)
return totalCalculator.Invoke(list);
else
throw new NotImplementedException("Total Func must be impelmented");
}
}
private void OnPropertyChanged(String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public int Count
{
get
{
if (countCalculator != null)
return countCalculator.Invoke(list);
else
throw new NotImplementedException("Count Func must be implemented");
}
}
}用法:
public class MyDocViewModel: GenericListViewModel<DocView>
{
public MyDocViewModel()
: base(
(list) =>
{
return list.Sum(x => x.Price);
},
(list) =>
{
return list.Count;
}
)
{
}
}https://stackoverflow.com/questions/24701651
复制相似问题