绑定到 ObservableCollection 以显示前 X 个项目 c# WPF
Binding to an ObservableCollection to show the first X number of items c# WPF
背景说明
好的,所以我目前正在将 ContextMenu
ItemsSource
绑定到 ObservableCollection
让我们说 TypeA
以下代码在单例classDataStore
内
private ObservableCollection<TypeA> TypeACollection = new ObservableCollection<TypeA>();
public ObservableCollection<TypeA> GetTypeACollection
{
get { return TypeACollection; }
}
public ObservableCollection<TypeA> GetFirstFiveTypeACollection
{
get
{
return TypeACollection.Take(5);
}
}
现在我已经使用以下 XAML 代码成功地将 ItemsControl
绑定到 GetTypeACollection
:
下面的代码在MainWindow.xaml
内
<ItemsControl x:Name="TypeAList" ItemsSource="{Binding GetTypeACollection, Source={StaticResource DataStore}, UpdateSourceTrigger=PropertyChanged}" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<User_Controls:TypeAUserControl Type="{Binding }"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
这按预期工作,显示 TypeAUserControl
,格式正确,符合来自 TypeA
的数据
现在,当我尝试通过将 ItemsSource
绑定到 GetFirstFiveTypeACollection
在 ContextMenu
MenuItem
上重复此操作时,我最初看到了预期的结果,但是在删除 TypeA
对象 MainWindow ItemsControl
在 ContextMenu
未更新的地方更新。
我认为这是因为绑定本身位于 ContextMenu
和 'new' ObservableCollection<TypeA>
之间(如 GetFirstFiveTypeAColletion
所示)。
我也尝试过使用 IValueConverter
以下代码在class ValueConverters
中
public class ObservableCollectionTypeAResizeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
ObservableCollection<TypeA> TypeACollection = value as ObservableCollection<TypeA>;
return TypeACollection.Take(System.Convert.ToInt32(parameter));
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
我试过的XAML代码。
使用 IValueConverter
<MenuItem Header="First 5 Type A" Name="MI_FirstFiveTypeA"
ItemsSource="{Binding DATA_STORE.GetTypeACollection, ConverterParameter=5,
Converter={StaticResource ObservableCollectionTypeAResizeConverter},
Source={StaticResource DataStore}}"
/>
使用 GetFirstFiveTypeACollection
<MenuItem Header="First 5 Type A" Name="MI_FirstFiveTypeA"
ItemsSource="{Binding DATA_STORE.RecentTimers, Source={StaticResource DataStore},
UpdateSourceTrigger=PropertyChanged}"
/>
我不知道接下来要尝试做什么或我应该怎么做,任何帮助将不胜感激!
编辑
好的,所以我更改了以下内容
DataStore.cs
private ObservableCollection<TimerType> TimerTypes = new ObservableCollection<TimerType>();
public ObservableCollection<TimerType> getTimerTypes
{
get
{
return new ObservableCollection<TimerType>(TimerTypes.OrderByDescending(t => t.LastUsed));
}
}
public ObservableCollection<TimerType> RecentTimers
{
get
{
return new ObservableCollection<TimerType>(TimerTypes.OrderByDescending(t => t.LastUsed).Take(5));
}
}
public event PropertyChangedEventHandler PropertyChanged;
// Create the OnPropertyChanged method to raise the event
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
//THIS IS IN THE ADD METHOD
TimerTypes.Add(timer);
NotifyPropertyChanged("getTimerTypes");
NotifyPropertyChanged("RecentTimers");
NotifyPropertyChanged("TimerTypes");
//THIS IS IN THE REMOVE METHOD
TimerTypes.Remove(Timer);
NotifyPropertyChanged("getTimerTypes");
NotifyPropertyChanged("RecentTimers");
NotifyPropertyChanged("TimerTypes");
MainWindow.xaml
<ItemsControl x:Name="TimersList" ItemsSource="{Binding Path=getTimerTypes, UpdateSourceTrigger=PropertyChanged}" >
MainWindow.xaml.cs
//Lists are populated in DataStore.cs before this.
DataContext = DataStore.DATA_STORE;
InitializeComponent();
NotifyIcon.xaml
<MenuItem Header="Recent Timers" Name="MIRecent" ItemsSource="{Binding RecentTimers, UpdateSourceTrigger=PropertyChanged}"/>
NotifyIcon.xaml.cs
DataContext = DataStore.DATA_STORE;
InitializeComponent();
所以一切都在开始时正确绑定,但是当删除 TimerType
时,PropertyChangedEventHandler
始终为 NULL。我认为这是一个 DataContext
问题,但我很确定我的 DataContext
和所有 Bindings
现在都正确了吗?
创建单例实例
private static readonly DataStore Instance = new DataStore();
private DataStore() { }
public static DataStore DATA_STORE
{
get { return Instance; }
set { }
}
不幸的是,通过使用 Take
(或任何 LINQ 方法),您会直接返回 IEnumerable
。当您绑定到它时,没有 INotifyCollectionChanged
,因此对集合的更改不会导致 UI 更新。
由于缺少 INotifyCollectionChanged
,因此没有真正的解决方法。当你 add/remove 项目强制 UI 重新枚举 IEnumerable
.[= 时,你最好的选择是针对你的 "subset" 属性 提高 PropertyChanged
16=]
您或许可以使用 CollectionView 来解决这个问题
public class MyViewModel
{
CollectionView _mostRecentDocuments;
public MyViewModel()
{
Documents = new ObservableCollection<Document>();
_mostRecentDocuments = new CollectionView(Documents);
_mostRecentDocuments .Filter = x => Documents.Take(5).Contains(x);
}
public ObservableCollection<Document> Documents { get; private set; }
public CollectionView MostRecentDocuments
{
get
{
return _mostRecentDocuments;
}
}
}
背景说明
好的,所以我目前正在将 ContextMenu
ItemsSource
绑定到 ObservableCollection
让我们说 TypeA
以下代码在单例classDataStore
内private ObservableCollection<TypeA> TypeACollection = new ObservableCollection<TypeA>();
public ObservableCollection<TypeA> GetTypeACollection
{
get { return TypeACollection; }
}
public ObservableCollection<TypeA> GetFirstFiveTypeACollection
{
get
{
return TypeACollection.Take(5);
}
}
现在我已经使用以下 XAML 代码成功地将 ItemsControl
绑定到 GetTypeACollection
:
下面的代码在MainWindow.xaml
内<ItemsControl x:Name="TypeAList" ItemsSource="{Binding GetTypeACollection, Source={StaticResource DataStore}, UpdateSourceTrigger=PropertyChanged}" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<User_Controls:TypeAUserControl Type="{Binding }"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
这按预期工作,显示 TypeAUserControl
,格式正确,符合来自 TypeA
现在,当我尝试通过将 ItemsSource
绑定到 GetFirstFiveTypeACollection
在 ContextMenu
MenuItem
上重复此操作时,我最初看到了预期的结果,但是在删除 TypeA
对象 MainWindow ItemsControl
在 ContextMenu
未更新的地方更新。
我认为这是因为绑定本身位于 ContextMenu
和 'new' ObservableCollection<TypeA>
之间(如 GetFirstFiveTypeAColletion
所示)。
我也尝试过使用 IValueConverter
以下代码在class ValueConverters
中public class ObservableCollectionTypeAResizeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
ObservableCollection<TypeA> TypeACollection = value as ObservableCollection<TypeA>;
return TypeACollection.Take(System.Convert.ToInt32(parameter));
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
我试过的XAML代码。
使用 IValueConverter
<MenuItem Header="First 5 Type A" Name="MI_FirstFiveTypeA"
ItemsSource="{Binding DATA_STORE.GetTypeACollection, ConverterParameter=5,
Converter={StaticResource ObservableCollectionTypeAResizeConverter},
Source={StaticResource DataStore}}"
/>
使用 GetFirstFiveTypeACollection
<MenuItem Header="First 5 Type A" Name="MI_FirstFiveTypeA"
ItemsSource="{Binding DATA_STORE.RecentTimers, Source={StaticResource DataStore},
UpdateSourceTrigger=PropertyChanged}"
/>
我不知道接下来要尝试做什么或我应该怎么做,任何帮助将不胜感激!
编辑
好的,所以我更改了以下内容
DataStore.cs
private ObservableCollection<TimerType> TimerTypes = new ObservableCollection<TimerType>();
public ObservableCollection<TimerType> getTimerTypes
{
get
{
return new ObservableCollection<TimerType>(TimerTypes.OrderByDescending(t => t.LastUsed));
}
}
public ObservableCollection<TimerType> RecentTimers
{
get
{
return new ObservableCollection<TimerType>(TimerTypes.OrderByDescending(t => t.LastUsed).Take(5));
}
}
public event PropertyChangedEventHandler PropertyChanged;
// Create the OnPropertyChanged method to raise the event
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
//THIS IS IN THE ADD METHOD
TimerTypes.Add(timer);
NotifyPropertyChanged("getTimerTypes");
NotifyPropertyChanged("RecentTimers");
NotifyPropertyChanged("TimerTypes");
//THIS IS IN THE REMOVE METHOD
TimerTypes.Remove(Timer);
NotifyPropertyChanged("getTimerTypes");
NotifyPropertyChanged("RecentTimers");
NotifyPropertyChanged("TimerTypes");
MainWindow.xaml
<ItemsControl x:Name="TimersList" ItemsSource="{Binding Path=getTimerTypes, UpdateSourceTrigger=PropertyChanged}" >
MainWindow.xaml.cs
//Lists are populated in DataStore.cs before this.
DataContext = DataStore.DATA_STORE;
InitializeComponent();
NotifyIcon.xaml
<MenuItem Header="Recent Timers" Name="MIRecent" ItemsSource="{Binding RecentTimers, UpdateSourceTrigger=PropertyChanged}"/>
NotifyIcon.xaml.cs
DataContext = DataStore.DATA_STORE;
InitializeComponent();
所以一切都在开始时正确绑定,但是当删除 TimerType
时,PropertyChangedEventHandler
始终为 NULL。我认为这是一个 DataContext
问题,但我很确定我的 DataContext
和所有 Bindings
现在都正确了吗?
创建单例实例
private static readonly DataStore Instance = new DataStore();
private DataStore() { }
public static DataStore DATA_STORE
{
get { return Instance; }
set { }
}
不幸的是,通过使用 Take
(或任何 LINQ 方法),您会直接返回 IEnumerable
。当您绑定到它时,没有 INotifyCollectionChanged
,因此对集合的更改不会导致 UI 更新。
由于缺少 INotifyCollectionChanged
,因此没有真正的解决方法。当你 add/remove 项目强制 UI 重新枚举 IEnumerable
.[= 时,你最好的选择是针对你的 "subset" 属性 提高 PropertyChanged
16=]
您或许可以使用 CollectionView 来解决这个问题
public class MyViewModel
{
CollectionView _mostRecentDocuments;
public MyViewModel()
{
Documents = new ObservableCollection<Document>();
_mostRecentDocuments = new CollectionView(Documents);
_mostRecentDocuments .Filter = x => Documents.Take(5).Contains(x);
}
public ObservableCollection<Document> Documents { get; private set; }
public CollectionView MostRecentDocuments
{
get
{
return _mostRecentDocuments;
}
}
}