绑定到 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 绑定到 GetFirstFiveTypeACollectionContextMenu MenuItem 上重复此操作时,我最初看到了预期的结果,但是在删除 TypeA 对象 MainWindow ItemsControlContextMenu 未更新的地方更新。

我认为这是因为绑定本身位于 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;
        }
    }
}