[英]How do I change header content of a ListView after ObservableCollection is changed?
I have a ListView
with a grouping using a CollectionViewSource
. 我有一个使用
CollectionViewSource
进行分组的ListView
。 The items from ObservableCollection
are grouped by date. ObservableCollection
中的项目按日期分组。 I have a button in the group headers, which adds a new record with it's group date. 我在组标题中有一个按钮,它添加了一个新记录及其组日期。 I need to show this button only if there's less than 4 records in this group, or if an item from a group has a one of specific
Enum
values on a property. 仅当该组中的记录少于4条,或者某个组中的某项在属性上具有特定的
Enum
值之一时,才需要显示此按钮。
I've made a "filter" using Visibity
property and a custom converter of IMultiValueConverter
. 我使用
Visibity
属性和Visibity
的自定义转换器IMultiValueConverter
了一个“过滤器”。 The Problem is that the check happens only on the ListView initialization and doesn't occur after adding or editing items in the ObservableCollection
. 问题是检查仅在ListView初始化上进行,而在
ObservableCollection
添加或编辑项目后才进行检查。 How do I call Visibility check after collection change? 更改集合后如何调用可见性检查? Or maybe there's more optimized solution for my task?
也许有针对我的任务的更优化的解决方案?
View 视图
<Page.Resources>
<CollectionViewSource x:Key='src'
Source="{Binding TimesheetEntries}"
>
<CollectionViewSource.SortDescriptions>
<!--This will sort groups-->
<componentmodel:SortDescription PropertyName="Date" />
</CollectionViewSource.SortDescriptions>
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="Date" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</Page.Resources>
<StackPanel x:Name="MainStackPanel" Orientation="Vertical">
<ListView
x:Name="TimesheetEntriesListView"
Margin="10"
Grid.Row="1"
Grid.ColumnSpan="2"
ItemsSource="{Binding Source={StaticResource src}}"
SelectedItem="{Binding SelectedEntry, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
>
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Height="30" Margin="3" IsEnabled="{Binding IsEditable}">
<ComboBox
SelectedValuePath="Key" DisplayMemberPath="Value"
ItemsSource="{Binding EmploymentTypesDictionary, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
SelectedValue="{Binding SelectedEmployment, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Width="300"/>
<TextBox
Text="{Binding Hours, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, StringFormat=N2}"
Margin="5,0,0,0"
Height="Auto"
IsEnabled="{Binding HoursAvaliable}"
Width="70"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<StackPanel Margin="5,5,5,0" Orientation="Horizontal">
<Button Margin="5,0,10,0"
Content="+"
Command="{Binding Path=DataContext.AddNewTimesheetEntryCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Page}}}"
CommandParameter="{Binding Path=Name}"
>
<Button.Visibility>
<MultiBinding Converter="{tools:TimesheetListToVisibilityConverter}">
<Binding RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type Page}}" Path="DataContext.TimesheetEntries"/>
<Binding Path="Name" />
</MultiBinding>
</Button.Visibility>
</Button>
<TextBlock FontSize="14" Text="{Binding Path=Name, StringFormat='{}{0:dd/MM/yyyy, dddd}'}"/>
</StackPanel>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListView.GroupStyle>
</ListView>
</StackPanel>
TimesheetListToVisibilityConverter TimesheetListToVisibilityConverter
public class TimesheetListToVisibilityConverter : MarkupExtension, IMultiValueConverter
{
public TimesheetListToVisibilityConverter()
{
TrueValue = Visibility.Visible;
FalseValue = Visibility.Collapsed;
}
public Visibility TrueValue { get; set; }
public Visibility FalseValue { get; set; }
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
ObservableCollection<TimesheetEntryEntity> val = values[0] as ObservableCollection<TimesheetEntryEntity>;
DateTime Date;
bool AddingIsAllowed = false;
if (values[1] != null)
{
Date = (DateTime)values[1];
} else
{
throw new Exception("Дата группы записей была пустой");
}
var CurrentDateEntries = val.Where(x => x.Date == Date).ToList();
if (CurrentDateEntries.Count >= 4)
{
return FalseValue;
}
foreach (var item in CurrentDateEntries)
{
if ((int)item.SelectedEmployment >= 5 && (int)item.SelectedEmployment <= 12)
return FalseValue;
}
return true;
}
public object[] ConvertBack(
object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
}
Bind to a property that is set when you add items to the source collection, like for example the Items.Count
property of the ListView
: 绑定到将项目添加到源集合时设置的属性,例如
ListView
的Items.Count
属性:
<Button.Visibility>
<MultiBinding Converter="{tools:TimesheetListToVisibilityConverter}">
<Binding RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type Page}}" Path="DataContext.TimesheetEntries"/>
<Binding Path="Name" />
<Binding RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type ListView}}" Path="Items.Count"/>
</MultiBinding>
</Button.Visibility>
If you also want to converter to get invoked when a property of an individual item changes, you need to detect when this happens and explicitly raise a change notification for any of the data-bound properties. 如果还希望在单个项目的属性更改时调用转换器,则需要检测何时发生这种情况,并显式引发任何数据绑定属性的更改通知。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.