![](/img/trans.png)
[英]Applying where on ObservableCollection doesn't reflect on datagrid
[英]ObservableCollection doesn't reflect changes for Summary calculation
我在后面的代碼中有一個DataGrid
並帶有手動處理的ObservableCollection<T>
。 當我向后備列表中添加新項目或刪除其中一個項目時,將更新“ 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;
我認為問題在於將列表綁定到datagrid
以及轉換器不會在ItemSource
獲取更改,因為該屬性不會更改。 該集合不會觸發PropertyChanged
事件。 嘗試這個:
datagrid.ItemsSource = list;
並且在您的XAML中使用多重綁定上的轉換器。 集合更改時,對ItemsSource.Count
的綁定將觸發通知。 注意,您不需要將TextBlock
嵌入Label
。
<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
。
完整的解決方案:
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));
}
}
}
編輯
這是視圖模型的更具體的通用實現,使您可以將相同的邏輯用於不同的項目類型,以提供自定義的總計和計數計算器:
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;
}
)
{
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.