C# 如何在ItemsControl组中绑定小计
想象一下这个DTO类:C# 如何在ItemsControl组中绑定小计,c#,wpf,xaml,data-binding,C#,Wpf,Xaml,Data Binding,想象一下这个DTO类: class LineItem : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; public string Description { get; set; } private decimal m_Amount; public decimal Amount { get { return m_Amou
class LineItem : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public string Description { get; set; }
private decimal m_Amount;
public decimal Amount
{
get { return m_Amount; }
set
{
if (m_Amount == value)
return;
m_Amount = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("Amount"));
}
}
}
还有像这样的装订:
<ItemsControl ItemsSource="{Binding LineItems}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<DockPanel>
<TextBox Text="{Binding Amount}"
DockPanel.Dock="Right" Width="50" />
<TextBlock Text="{Binding Description}" />
</DockPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<TextBlock HorizontalAlignment="Right"
Text="{Binding LineItems,
Converter={StaticResource MyConverter}}" />
这看起来像:
现在,我希望底部有一个总数。此外,我希望它在金额变化时更新
大概是这样的:
<ItemsControl ItemsSource="{Binding LineItems}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<DockPanel>
<TextBox Text="{Binding Amount}"
DockPanel.Dock="Right" Width="50" />
<TextBlock Text="{Binding Description}" />
</DockPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<TextBlock HorizontalAlignment="Right"
Text="{Binding LineItems,
Converter={StaticResource MyConverter}}" />
为此:
但是什么是MyConverter?而且,这是一种正确的方法吗
我的问题:
这不起作用,因为转换器仅在第一次绑定时才被调用。我希望它反映用户的更改,并且我需要处理未知数量的行项目。当然,我不是第一个这样做的人有办法吗?您可以改为绑定到一个专门表示
平均金额的属性(在“视图模型”上)并确保在PropertyChanged
上为每个LineItem
发送AverageAmount
属性的更改通知,以允许模型计算值,并让UI重新获取新值
然而,在仔细考虑了这样做的开销之后,我将研究类似于or(or)的东西,它应该处理所有的依赖性分析和更改通知。我们使用BindableLinq取得了巨大的成功,尽管在这个时候,启动它的人并没有积极地维护它
编辑:
举一个不使用我上面提到的库的后端示例(它删除了处理集合和属性更改事件的管道):
公共类ItemListViewModel:INotifyPropertyChanged
{
公共事件属性更改事件处理程序属性更改;
私有只读ObservableCollection _items=新ObservableCollection();
public ItemListViewModel()
{
_items.CollectionChanged+=已更改;
}
公共ICollection项{get{return\u Items;}}
私有void OnItemChanged(对象发送方,NotifyCollectionChangedEventArgs e)
{
开关(电动)
{
案例NotifyCollectionChangedAction。添加:
e、 NewItems.Cast().ToList().ForEach(iv=>iv.PropertyChanged+=OnItemPropertyChanged);
打破
案例NotifyCollectionChangedAction。删除:
e、 OldItems.Cast().ToList().ForEach(iv=>iv.PropertyChanged-=OnItemPropertyChanged);
打破
违约:
抛出新的NotImplementedException();
}
}
私有void OnItemPropertyChanged(对象发送方,PropertyChangedEventArgs e)
{
如果(例如,PropertyName==“值”)
{
if(PropertyChanged!=null)
PropertyChanged(即新PropertyChangedEventArgs(“AverageValue”);
}
}
公共双平均值
{
获取{returnitems.Average(iv=>iv.Value);}
}
}
公共类ItemViewModel:INotifyPropertyChanged
{
公共事件属性更改事件处理程序属性更改;
公共字符串族{get;set;}
私人国际货币单位价值;
公共整数值
{
获取{返回m_值;}
设置
{
如果(m_值==值)
返回;
m_值=值;
if(PropertyChanged!=null)
PropertyChanged(即新PropertyChangedEventArgs(“价值”);
}
}
}
然后,XAML中的ItemsControl直接绑定到视图模型的Items属性,average值绑定到AverageValue属性。它现在将处理所需的通知
要在另一个级别添加分组,您必须引入另一个类“ItemGroupViewModel”,该类将监视父项集合的更改。我会将属性更改侦听器添加到所有项目中,如果它们更改了其族属性,则从本地项目集合中添加/删除。如果他们更改了Value属性,则为AverageValue属性触发PropertyChanged
注意:BindableLinq也支持分组操作。结果如下:
<ItemsControl ItemsSource="{Binding LineItems}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<DockPanel>
<TextBox Text="{Binding Amount}"
DockPanel.Dock="Right" Width="50" />
<TextBlock Text="{Binding Description}" />
</DockPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<TextBlock HorizontalAlignment="Right"
Text="{Binding LineItems,
Converter={StaticResource MyConverter}}" />
这是政务司司长:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
// used to force databinding to refresh
public int FakeProperty
{
get { return (int)GetValue(FakePropertyProperty); }
set { SetValue(FakePropertyProperty, value); }
}
public static readonly DependencyProperty FakePropertyProperty =
DependencyProperty.Register("FakeProperty",
typeof(int), typeof(MainWindow), new UIPropertyMetadata(0));
private void TextBox_TextChanged(object sender,
System.Windows.Controls.TextChangedEventArgs e)
{
FakeProperty++;
}
}
public class Item : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public string Family { get; set; }
private int m_Value;
public int Value
{
get { return m_Value; }
set
{
if (m_Value == value)
return;
m_Value = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("Value"));
}
}
}
public class Items : ObservableCollection<Item>
{
public Items()
{
this.Add(new Item { Family = "One", Value = 1 });
this.Add(new Item { Family = "One", Value = 2 });
this.Add(new Item { Family = "Two", Value = 3 });
this.Add(new Item { Family = "Two", Value = 4 });
this.Add(new Item { Family = "Two", Value = 5 });
this.Add(new Item { Family = "Three", Value = 6 });
this.Add(new Item { Family = "Three", Value = 7 });
}
}
public class SumConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
var _Default = 0;
if (values == null || values.Length != 2)
return _Default;
var _Collection = values[0] as System.Collections.IEnumerable;
if (_Collection == null)
return _Default;
var _Items = _Collection.Cast<Item>();
if (_Items == null)
return _Default;
var _Sum = _Items.Sum(x => x.Value);
return _Sum;
}
public object[] ConvertBack(object value, Type[] targetTypes, obje
ct parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
公共部分类主窗口:窗口
{
公共主窗口()
{
初始化组件();
}
//用于强制数据绑定刷新
公共伪造财产
{
获取{return(int)GetValue(FakePropertyProperty);}
set{SetValue(FakePropertyProperty,value);}
}
公共静态只读从属属性FakeProperty属性属性=
DependencyProperty.Register(“FakeProperty”,
typeof(int)、typeof(MainWindow)、新的UIPropertyMetadata(0);
私有void TextBox\u TextChanged(对象发送方,
System.Windows.Controls.textchangedventargs(e)
{
伪属性++;
}
}
公共类项目:INotifyPropertyChanged
{
公共事件属性更改事件处理程序属性更改;
公共字符串族{get;set;}
私人国际货币单位价值;
公共整数值
{
获取{返回m_值;}
设置
{
如果(m_值==值)
返回;
m_值=值;
if(PropertyChanged!=null)
PropertyChanged(即新PropertyChangedEventArgs(“价值”);
}
}
}
公共类项目:ObservableCollection
{
公共物品()
{
添加(新项{Family=“One”,Value=1});
添加(新项{Family=“One”,值=2});
添加(新项{Family=“Two”,Value=3});
添加(新项{Family=“Two”,值=4});
添加(新项{Family=“Two”,值=5});
添加(新项{Family=“Three”,Value=6});
添加(新项{Family=“Three”,Value=7});
}
}
公共类SumConverter:IMultiValueConverter
{
公共对象转换(对象[]值,类型targetType,
对象参数,System.Globalization.CultureInfo(区域性)