c# - 如何过滤 CollectionContainer
问题描述
我在结合使用CompositeCollection执行ICollectionView过滤时遇到问题。
插图描述了我想要实现的目标: 带有过滤器文本框、项目集合和“添加”按钮的窗口
要求:
- “添加”按钮必须是WrapPanel的一部分
- 过滤应该通过ICollectionView.View.Filter执行
调试窗口.xaml:
<StackPanel>
<TextBox Text="{Binding TextBoxText, UpdateSourceTrigger=PropertyChanged}" Margin="5" BorderBrush="Black"/>
<ItemsControl BorderBrush="Gray">
<!-- Resources -->
<ItemsControl.Resources>
<CollectionViewSource x:Key="ColVSKey"
Source="{Binding MyCollection}"/>
</ItemsControl.Resources>
<!-- Items Source -->
<ItemsControl.ItemsSource>
<CompositeCollection>
<CollectionContainer Collection="{Binding Source={StaticResource ColVSKey}}"/>
<Button Content="Add another one" Margin="5"/>
</CompositeCollection>
</ItemsControl.ItemsSource>
<!-- Item Template -->
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"
Background="Gray"
Margin="10"
Padding="5"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
<!-- Items Panel -->
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</StackPanel>
DebugWindow.xaml.cs:
public partial class DebugWindow : Window, INotifyPropertyChanged
{
private string _textBoxText = "";
public ObservableCollection<string> MyCollection { get; set; }
public Predicate<object> FilterFunction { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
private ICollectionView view;
public string TextBoxText
{
get
{
return _textBoxText;
}
set
{
if (value == _textBoxText)
return;
_textBoxText = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(nameof(TextBoxText)));
if (view != null)
view.Refresh();
}
}
public DebugWindow()
{
InitializeComponent();
MyCollection = new ObservableCollection<string>() { "one", "two", "Three", "four", "five", "six", "seven", "Eight" };
FilterFunction = new Predicate<object>((o) => Filter(o));
view = CollectionViewSource.GetDefaultView(MyCollection);
if (view != null)
view.Filter = new Predicate<object>((o) => Filter(o));
this.DataContext = this;
}
public bool Filter(object v)
{
string s = (string)v;
bool ret = false;
if (s.IndexOf(TextBoxText) != -1)
ret = true;
return ret;
}
}
问题是,这是与Resources中定义的CollectionViewSourceview = CollectionViewSource.GetDefaultView(MyCollection);
相关联的View,而不是CollectionContainer的 View 。所以刷新了错误的View,显示的View根本不刷新。
我能够通过扩展CollectionContainer来实现所需的行为,并连接到 CollectionChanged 事件:
public class MyCollectionContainer : CollectionContainer
{
private ICollectionView _view;
public ICollectionView View
{
get
{
return _view;
}
}
public MyCollectionContainer()
{
this.CollectionChanged += MyCollectionContainer_CollectionChanged;
}
private void MyCollectionContainer_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (_view == null && Collection != null && MyFilter != null)
{
_view = CollectionViewSource.GetDefaultView(Collection);
_view.Filter += MyFilter;
}
}
}
并将其暴露给代码隐藏:
...in XAML...
<CompositeCollection>
<local:MyCollectionContainer x:Name="MyCollectionContainer" Collection="{Binding Source={StaticResource ColVSKey}}"/>
<Button Content="Add another one" Margin="5"/>
</CompositeCollection>
...in constructor...
MyCollectionContainer.MyFilter = new Predicate<object>((o) => Filter(o));
...in TextBoxText property set...
if(MyCollectionContainer.View!=null)
MyCollectionContainer.View.Refresh();
问题: 有没有办法在不将控件暴露给代码隐藏的情况下实现我需要的行为?是否可以将 MVVM 绑定到CollectionContainer的视图?
在此先感谢,很抱歉发了很长的帖子。
解决方案
我找到了一个优雅的解决方案来解决我的问题。感谢Thomas Levesque 的 .NET 博客上的文章,该文章在此答案中被引用:CollectionContainer doesn't bind my Collection我可以简单地执行绑定,并且ICollectionView
获得的
CollectionViewSource.GetDefaultView(MyCollection);
是正确的要刷新的。
BindingProxy.cs(感谢 Thomas Levesque)
public class BindingProxy : Freezable
{
#region Overrides of Freezable
protected override Freezable CreateInstanceCore()
{
return new BindingProxy();
}
#endregion
public object MyData
{
get { return (object)GetValue(MyDataProperty); }
set { SetValue(MyDataProperty, value); }
}
public static readonly DependencyProperty MyDataProperty =
DependencyProperty.Register("MyData", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
}
更新的 XAML:
<ItemsControl>
<ItemsControl.Resources>
<local:BindingProxy x:Key="proxy" MyData="{Binding Path=MyCollection}"/>
</ItemsControl.Resources>
<ItemsControl.ItemsSource>
<CompositeCollection>
<CollectionContainer Collection="{Binding Source={StaticResource proxy}, Path=MyData}"/>
<Button Content="Add another one" Margin="5"/>
</CompositeCollection>
</ItemsControl.ItemsSource>
...
</ItemsControl>
推荐阅读
- angular - 如何在 Angular 应用程序的 If 语句中验证数组值?
- php - 为资源列表中的每个元素添加图标(完整日历)
- android - 刷新 ListView 但在后台页面上
- python - 有没有办法从 gdal 数组和绘图中获取 RGB?
- ios - 如何在 SwiftUI 上将视图设置为 keyWindow 的顶部
- opengl - 如何使用 gstreamer crates 从 BufferRef 中提取 GL 纹理 ID?
- firebase - 将应用程序部署到 Firebase 时出现问题,并且所有配置文件都列在浏览器中
- django - Django 自定义身份验证表单。如何显示错误信息
- r - 如何声明根据列名更改列值的 ifelse 条件?(剧透:我在北美尝试过的结果)
- mysql - MySQL JSON_OBJECT + CONCAT & GROUP_CONCAT 作为别名 & 截断/最大长度