1

我有一个类型的对象列表Emblem,我在LongListMultiSelector. 我只想展示那些尚未实现的。我可以选择一个或多个项目并将它们更改为,IsAchieved = true但问题是它们不会立即消失,UI 不会自动更新。

我认为这不会是一个问题,因为我使用了ObservableCollection<T>. 然后我发现如果一个项目的属性发生变化,集合是不会通知的。结果实现了INotifyPropertyChanged接口,但这也不起作用。

在这里,我发现了以下与此问题相同的问题(以及更多问题):

我也尝试实现了的用法,TrulyObservableCollection<T>但也没有结果。这就是我所拥有的

XAML 控制:

<toolkit:LongListMultiSelector Name="EmblemsList"
                               ItemsSource="{Binding Emblems}"
                               Background="Transparent"
                               LayoutMode="List"
                               ItemTemplate="{StaticResource ItemTemplate}" />

项目通过以下方式绑定EmblemsViewModel

public class EmblemsViewModel
{
    public EmblemsViewModel()
    {
        Emblems = new TrulyObservableCollection<Emblem>();
    }

    public TrulyObservableCollection<Emblem> Emblems { get; set; }
}

//Usage on the page
DataContext = new EmblemsViewModel { Emblems = DB.GetEmblems() }

Emblem课程如下:

public class Emblem : Achievement
{
    public int Level { get; set; }
}

public abstract class Achievement : INotifyPropertyChanged
{
    private bool _isAchieved;

    public string Description { get; set; }

    public bool IsAchieved
    {
        get { return _isAchieved; }
        set
        {
            if (_isAchieved != value)
            {
                _isAchieved = value;
                NotifyPropertyChanged("IsAchieved");
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

}

我错过了什么/做错了什么,阻止了它的工作?

更新:

我已应用 aCollectionViewSource来应用过滤,但现在没有显示任何项目。

//Reference to the CollectionViewSource
_viewSource = (CollectionViewSource)Resources["EmblemsViewSource"];

//3 options in the ListBox: all, achieved & unachieved
private void FilterListBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
{
    var selectedItem = ((ListBoxItem)FilterListBox.SelectedItem).Content.ToString();

    switch (selectedItem)
    {
        case "achieved": _filter = Filter.Achieved; _viewSource.Filter += new FilterEventHandler(CollectionViewSource_Filter); break;
        case "unachieved": _filter = Filter.Unachieved; _viewSource.Filter += new FilterEventHandler(CollectionViewSource_Filter); break;
        default: _filter = Filter.All; _viewSource.Filter -= new FilterEventHandler(CollectionViewSource_Filter); break;
    } 
}

private void CollectionViewSource_Filter(object sender, FilterEventArgs e)
{
    var item = e.Item as Emblem;

    switch (_filter)
    {
        case Filter.Achieved: e.Accepted = item.IsAchieved; break;
        case Filter.Unachieved: e.Accepted = !item.IsAchieved; break;
        case Filter.All: e.Accepted = true; break;
    }
}

XAML:

<CollectionViewSource x:Key="EmblemsViewSource" Source="{Binding Emblems}" />

<toolkit:LongListMultiSelector Name="EmblemsList"
                               ItemsSource="{Binding Source={StaticResource EmblemsViewSource}}"
                               Background="Transparent"
                               LayoutMode="List"
                               ItemTemplate="{StaticResource ItemTemplate}" />
4

3 回答 3

1

我已经实现了一个ObservableCollectionView类,您可以在其上设置一个Filter(谓词)并且可以跟踪所包含项目的更改并在项目发生更改时重新过滤......

看看https://mytoolkit.codeplex.com/wikipage?title=ObservableCollectionView

于 2014-12-16T08:37:54.037 回答
1

一种解决方案可能是您创建一个从 派生的新集合ObservableCollection并添加一个新属性,例如。FilteredItems.

主窗口

public partial class MainWindow : Window
{
    FilterableObservableCollection items;

    public MainWindow()
    {

        items = new FilterableObservableCollection()
        {
            new ListViewItem() { Name = "Hallo", IsArchived = false },
            new ListViewItem() { Name = "world", IsArchived = true },
            new ListViewItem() { Name = "!!!", IsArchived = false }
        };

        InitializeComponent();
    }

    public FilterableObservableCollection MyItems
    {
        get { return items; }
    }

    private void CheckBox_Checked(object sender, RoutedEventArgs e)
    {
        items.NotArchivedOnlyFilterEnabled = (sender as CheckBox).IsChecked.Value;
    }

    private void CheckBox_Unchecked(object sender, RoutedEventArgs e)
    {
        items.NotArchivedOnlyFilterEnabled = (sender as CheckBox).IsChecked.Value;
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        items.Add(new ListViewItem() { Name = "Item" + (items.Count + 1), IsArchived = items.Count % 2 == 0 });
    }
}

自定义可观察集合

public class FilterableObservableCollection : ObservableCollection<ListViewItem>
{
    private bool notArchivedOnlyFilterEnabled;

    public IEnumerable<ListViewItem> FilteredItems
    {
        get
        {
            if (notArchivedOnlyFilterEnabled)
            {
                return this.Where(x => x.IsArchived == false);

            }
            else
            {
                return this;
            }
        }
    }

    public bool NotArchivedOnlyFilterEnabled
    {
        get { return notArchivedOnlyFilterEnabled; }
        set
        {
            notArchivedOnlyFilterEnabled = value;
            OnPropertyChanged(new PropertyChangedEventArgs("FilteredItems"));
        }
    }
}

数据项

public class ListViewItem
{
    public string Name { get; set; }

    public bool IsArchived { get; set; }
}

XAML

<Window x:Class="ObservableCollectionDemo1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525"
        DataContext="{Binding RelativeSource={RelativeSource Self}}"
        xmlns:c="clr-namespace:ObservableCollectionDemo1">
    <Grid>
        <ListView HorizontalAlignment="Left" Height="142" Margin="81,47,0,0" VerticalAlignment="Top" Width="302" x:Name="listView" DataContext="{Binding MyItems}" ItemsSource="{Binding FilteredItems}">
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}"  Width="100"/>
                    <GridViewColumn Header="Is Archived" DisplayMemberBinding="{Binding IsArchived}" Width="100"/>
                </GridView>
            </ListView.View>
        </ListView>
        <CheckBox Content="Is Not Archived" HorizontalAlignment="Left" Margin="278,194,0,0" VerticalAlignment="Top" Checked="CheckBox_Checked" Unchecked="CheckBox_Unchecked"/>
        <Button Content="New Item" HorizontalAlignment="Left" Margin="278,214,0,0" VerticalAlignment="Top" Width="105" Click="Button_Click"/>

    </Grid>
</Window>
于 2014-12-16T07:59:46.883 回答
1

您只需对集合设置一次过滤器,而不是每次过滤器选项更改时。一次调用

_viewSource.Filter += new FilterEventHandler(CollectionViewSource_Filter);

应该是你所需要的,然后在你的列表框中选择改变你可以调用_viewSource。Refresh()强制过滤谓词重新评估列表项。

另一种选择可能是让表示标志的 XAML 数据模板将可见性属性直接绑定到使用转换器的IsAchieved属性:Emblem

<DataTemplate>
  <Border Visibility="{Binding IsAchieved, Converter={StaticResource BoolVisibilityConverter}}">
...

ValueConverterBoolVisibilityConverter在哪里。

您必须尝试一下,看看它是否适合您的场景 - 运行大量的值转换器可能会对大型数据集造成伤害,但它的优点是简单!

于 2014-12-16T08:26:57.527 回答