的ObservableCollection 1 3的列表视图取决于某些属性 [英] ObservableCollection to 1 of 3 listviews depending on some property

查看:294
本文介绍了的ObservableCollection 1 3的列表视图取决于某些属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

目前,我有一个名为一个ObservableCollection MYLIST 被绑定到在ListView中的ItemSource。这也从MYLIST添加和删除的项目。

我要的是在基于一些标准对每个列表视图中添加项目。更具体的,如果属性状态是是的项目应该去的第一个列表视图 MyListview ,如果是否转到第二个列表视图 MySecondListview 如果状态==和属性日期这是今天一个DateTime属性点,然后它到第三列表视图。

我的MainPage code是:

 公共密封部分类的MainPage:页
    {
        私人的ObservableCollection< MyClass的> MYLIST =新的ObservableCollection< MyClass的>();
        公众的MainPage()
        {
            this.InitializeComponent();
            的DataContext = MYLIST;
        }
         私人无效Add_Click(对象发件人,Windows.UI.Xaml.RoutedEventArgs E)
        {
            MyList.Add(新MyClass的(是,新的日期时间(2015年,5,4)));
        }        私人无效Delete_Click(对象发件人,Windows.UI.Xaml.RoutedEventArgs E)
        {
            MyList.Remove((MyClass的)MyListview.SelectedItem);
        }
    }

我的主页XAML是:

 <页
    X:类=App17.MainPage
    的xmlns =htt​​p://schemas.microsoft.com/winfx/2006/xaml/$p$psentation
    的xmlns:X =htt​​p://schemas.microsoft.com/winfx/2006/xaml
    XMLNS:地方=使用:APP17
    的xmlns:D =htt​​p://schemas.microsoft.com/ex$p$pssion/blend/2008
    的xmlns:MC =htt​​p://schemas.openxmlformats.org/markup-compatibility/2006
    MC:可忽略=D>    <&Viewbox控件GT;        <网格背景={ThemeResource ApplicationPageBackgroundThemeBrush}HEIGHT =768WIDTH =1366>
            <按钮X:名称=删除CONTENT =删除的Horizo​​ntalAlignment =左HEIGHT =116保证金=376,89,0,0VerticalAlignment =评出的WIDTH =224点击=Delete_Click />
            <按钮X:名称=添加CONTENT =增加的Horizo​​ntalAlignment =左HEIGHT =116保证金=111,89,0,0VerticalAlignment =评出的WIDTH =214点击=Add_Click />
            < ListView的X:名称=MyListview的Horizo​​ntalAlignment =左HEIGHT =497保证金=71,261,0,0VerticalAlignment =评出的WIDTH =349的ItemsSource ={结合}/>
            < ListView的X:名称=MySecondListview的Horizo​​ntalAlignment =左HEIGHT =497保证金=468,261,0,0VerticalAlignment =评出的WIDTH =317/>
            < ListView的X:名称=MyThirdListview的Horizo​​ntalAlignment =左HEIGHT =497保证金=893,261,0,0VerticalAlignment =评出的WIDTH =317/>        < /网格和GT;
    < / Viewbox控件>
< /页>

我的班级code是:

  MyClass类
{
    公共字符串状态{搞定;组; }
    公众的DateTime日期{搞定;组; }    公共MyClass的(串状态,日期为准)
    {
        状态=地位;
        日期=日期;
    }
}


解决方案

唉。所以,我并没有意识到这一点,但事实证明,WinRT的(即Windows应用商店的应用程序)不支持在的ICollectionView 过滤。好像每次我转身的时候,我发现另一个XAML / WPF功能,被莫名其妙地从WinRT的省略,这是其中之一。

所以,虽然这将是微不足道的WPF来完成(只创建一个 Col​​lectionViewSource 对象,订阅过滤器事件,并绑定到该对象的查看),这原来是多一点的WinRT的麻烦的。

目前已经有一些相关的文章,其中包括对堆栈溢出提供替代方案。例如:

这是第二个是一个非常复杂的实现支持过滤等操作。这是矫枉过正你的目的,但你可能会在未来找到你想使用的功能,它包括

第一个例子,而规模更适合你的问题,走近了问题,有些不同的方式比我会的。特别是,它实现了一个的ObservableCollection< T> 的子类,反过来有一个单一视图。这$ P $从正在为一个集合,许多意见的情况非常有用pvents它。

所以我写了一个的ObservableCollection< T> 这是同样的,但它本身是视图,并引用的独立实例的ObservableCollection< T> 。你可以使用这个类,我称之为的多个实例 FilteredObservableCollection< T> ,根据您的需要,同时仍保持单源集合。每个视图将自身根据需要进行更新,根据过滤器,当源集合改变。

<告诫指数=0>

在这种方法中(原灵感我的课,还有我自己),绑定的观点本身就是一个的ObservableCollection< T> 。特别是,这是的的只读集合。这些观点对象的任何消费者不要尝试直接修改视图对象,即使他们可以是非常重要的。他们只应该永远显示的对象。

上面的第二个链接是在这方面更好,因为它是实现一个实际的的ICollectionView 接口,这解决了问题的可变性。坦率地说,这将是从一个code维修点好做的方式,这样可以很清楚什么样的对象是真正的名单,什么对象是刚刚的意见。

但事实是,这种方式是一个的很多的更简单,更容易实现。只是要小心使用它,你就不会受到伤害。 :)

< /警告>

<告诫指数=1>

了解对方非常重要的限制是,这个实施将的的上更改过滤器逻辑更新查看集合(即如果你传递一个 predicate< T> 本身取决于一些可变状态的地方),或者更改显示的数据(即如果由过滤器正在检查一个属性在一个被修改或以上显示的数据项)。

这些限制可以以各种不同的方式来解决,但这样做将显著增加这个答案的复杂性。我想尝试让事情变得简单。这是我的希望,仅仅指出这些局限性出来就足够了,以确保如果你碰到你需要更活泼的视图实现的情况下,你是知道的局限性,知道你要扩展这个解决方案来支持您的需要。

< /警告>

这班风这样看:

 公共类FilteredObservableCollection< T> :与的ObservableCollection LT; T>
{
    私人predicate< T> _过滤;    公共FilteredObservableCollection(的ObservableCollection< T>源,predicate< T>过滤器)
        :基座(source.Where(项目=过滤器过滤(项)))
    {
        source.CollectionChanged + = source_CollectionChanged;
        _filter =滤波器;
    }    私人无效_Fill(的ObservableCollection< T>源)
    {
        明确();
        的foreach(源牛逼项)
        {
            如果(_filter(项目))
            {
                新增项目);
            }
        }
    }    私人诠释这个[T项目]
    {
        得到
        {
            INT foundIndex = -1;
            对于(INT指数= 0;指数 - LT;计数;指数++)
            {
                如果(本[指数] .Equals(项目))
                {
                    foundIndex =指数;
                    打破;
                }
            }
            返回foundIndex;
        }
    }    私人无效source_CollectionChanged(对象发件人,NotifyCollectionChangedEventArgs E)
    {
        的ObservableCollection< T>来源=(的ObservableCollection< T>)发送;        开关(e.Action)
        {
        案例NotifyCollectionChangedAction.Add:
            的foreach(在e.NewItems牛逼项)
            {
                如果(_filter(项目))
                {
                    新增项目);
                }
            }
            打破;        案例NotifyCollectionChangedAction.Move:
            //如果没有更多的工作保持视图状态,这将是一样硬
            //找出其中的移动的项目应该去,因为它是只再生
            //整个视图。所以只是做了后者。
            _Fill(源);
            打破;        案例NotifyCollectionChangedAction.Remove:
            的foreach(在e.OldItems牛逼项)
            {
                //不要费心寻找的项目,如果它被过滤掉
                如果(_filter(项目))
                {
                    除去项目);
                }
            }
            打破;        案例NotifyCollectionChangedAction.Replace:
            对于(INT指数= 0;指数 - LT; e.OldItems.Count;指数++)
            {
                ŧ项目=(T)e.OldItems [指数]
                如果(_filter(项目))
                {
                    INT foundIndex =本[项目];                    如果(foundIndex == -1)
                    {
                        //即不应该发生
                        抛出新的异常(内部状态故障对象不是present,即使它应该是。);
                    }                    ŧ的newitem =(T)e.NewItems [指数]                    如果(_filter(的newitem))
                    {
                        这个[foundIndex] =的newitem;
                    }
                    其他
                    {
                        RemoveAt移除(foundIndex);
                    }
                }
                其他
                {
                    //该项目被替换未在过滤
                    //组数据。而不是做的工作要弄清楚
                    //其中新项目应该去,只是重新填充
                    //整个列表。 (同样的道理,作为移动事件)。
                    _Fill(源);
                }
            }
            打破;        案例NotifyCollectionChangedAction.Reset:
            _Fill(源);
            打破;
        }
    }
}

因此​​,带有辅助对象实施,建立你的用户界面非常简单。只要创建你想要你的数据的每个视图上面的类的新实例,并绑定到该实例。

在这个例子中,我返工你原来的UI相当广泛,清理了一点东西,并使其更容易观察这是怎么回事。我添加按钮来创建一个应该出现在每个视图中的项目,现在有四种观点:整个列表(在这里你可以选择和删除的项目),然后每一个三个过滤选项

通过这种方法,的DataContext 卷起被这个,而不是一个列表,因为我们希望获得个人意见。成员们还需要更改为公共​​属性,从而使XAML绑定引擎可以找到它们。这个例子假设他们将被初始化一次并没有改变;如果你希望绑定为可更新,你会想要让这些依赖关系属性或实施 INotifyPropertyChanged的的MainPage 类。

我还添加了的DataTemplate 为您的类,这样在每个列表中每个项目的presentation是有益的(即不是类型名称以外的东西)。

通过这一切,在XAML风这样看:

 <页
    X:类=TestSO30038588ICollectionView.MainPage
    的xmlns =htt​​p://schemas.microsoft.com/winfx/2006/xaml/$p$psentation
    的xmlns:X =htt​​p://schemas.microsoft.com/winfx/2006/xaml
    XMLNS:地方=使用:TestSO30038588ICollectionView
    的xmlns:D =htt​​p://schemas.microsoft.com/ex$p$pssion/blend/2008
    的xmlns:MC =htt​​p://schemas.openxmlformats.org/markup-compatibility/2006
    MC:可忽略=D>  < Page.Resources>
    <的DataTemplate X:键=myClassTemplate>
      < StackPanel的方向=横向>
        < TextBlock的文本={绑定状态}/>
        < TextBlock的文本={结合日期}保证金=20,0,0,0/>
      < / StackPanel的>
    < / DataTemplate中>
  < /Page.Resources>
  <&Viewbox控件GT;
    <网格背景={ThemeResource ApplicationPageBackgroundThemeBrush}HEIGHT =768WIDTH =1366>
      < Grid.ColumnDefinitions>
        < ColumnDefinition />
        < ColumnDefinition />
        < ColumnDefinition />
        < ColumnDefinition />
      < /Grid.ColumnDefinitions>
      < Grid.RowDefinitions>
        < RowDefinition高度=自动/>
        < RowDefinition高度=自动/>
        < RowDefinition />
      < /Grid.RowDefinitions>
      <按钮X:名称=删除CONTENT =删除
              的Horizo​​ntalAlignment =左VerticalAlignment =顶部
              高度=116宽度=224
              Grid.Row =0Grid.Column =0
              点击=Delete_Click/>
      <按钮X:名称=切换CONTENT =切换是/否
              的Horizo​​ntalAlignment =左VerticalAlignment =顶部
              高度=116宽度=224
              Grid.Row =1Grid.Column =0
              点击=Toggle_Click/>
      <按钮X:NAME =AddYesCONTENT =添加是
              的Horizo​​ntalAlignment =左VerticalAlignment =顶部
              高度=116宽度=214
              Grid.Row =0Grid.Column =1
              点击=AddYes_Click/>
      <按钮X:NAME =AddNoCONTENT =无添加
              的Horizo​​ntalAlignment =左VerticalAlignment =顶部
              高度=116宽度=214
              Grid.Row =0Grid.Column =2
              点击=AddNo_Click/>
      <按钮X:NAME =AddEmptyCONTENT =添加空
              的Horizo​​ntalAlignment =左VerticalAlignment =顶部
              高度=116宽度=214
              Grid.Row =0Grid.Column =3
              点击=AddEmpty_Click/>
      < ListView的X:名称=AllElementsList
                的ItemTemplate ={StaticResource的myClassTemplate}
                的Horizo​​ntalAlignment =左VerticalAlignment =顶部
                Grid.Row =2Grid.Column =0
                的ItemsSource ={结合MYLIST}/>
      < ListView的X:名称=MyListview
                的ItemTemplate ={StaticResource的myClassTemplate}
                的Horizo​​ntalAlignment =左VerticalAlignment =顶部
                Grid.Row =1Grid.Column =1Grid.RowSpan =2
                的ItemsSource ={结合yesList}/>
      < ListView的X:名称=MySecondListview
                的ItemTemplate ={StaticResource的myClassTemplate}
                的Horizo​​ntalAlignment =左VerticalAlignment =顶部
                Grid.Row =1Grid.Column =2Grid.RowSpan =2
                的ItemsSource ={结合NOLIST}/>
      < ListView的X:名称=MyThirdListview
                的ItemTemplate ={StaticResource的myClassTemplate}
                的Horizo​​ntalAlignment =左VerticalAlignment =顶部
                Grid.Row =1Grid.Column =3Grid.RowSpan =2
                的ItemsSource ={结合的emptyList}/>
    < /网格和GT;
  < / Viewbox控件>
< /页>

以及的MainPage code是这样的:

 公共密封部分类的MainPage:页
{
    公众的ObservableCollection< MyClass的> MYLIST {搞定;组; }
    公共FilteredObservableCollection< MyClass的> yesList {搞定;组; }
    公共FilteredObservableCollection< MyClass的> NOLIST {搞定;组; }
    公共FilteredObservableCollection< MyClass的> {的emptyList获得;组; }    公众的MainPage()
    {
        this.InitializeComponent();        MYLIST =新的ObservableCollection< MyClass的>();
        yesList =新FilteredObservableCollection< MyClass的>(MYLIST,项目= GT; item.Status ==是);
        NOLIST =新FilteredObservableCollection< MyClass的>(MYLIST,项目= GT; item.Status ==否);
        的emptyList =新FilteredObservableCollection< MyClass的>(MYLIST,项目= GT; item.Status ==&放大器;&安培; item.Date.Date == DateTime.Now.Date);        的DataContext =这一点;
    }    私人无效AddYes_Click(对象发件人,Windows.UI.Xaml.RoutedEventArgs E)
    {
        MyList.Add(新MyClass的(是,DateTime.Now));
    }    私人无效AddNo_Click(对象发件人,Windows.UI.Xaml.RoutedEventArgs E)
    {
        MyList.Add(新MyClass的(否,DateTime.Now));
    }    私人无效AddEmpty_Click(对象发件人,Windows.UI.Xaml.RoutedEventArgs E)
    {
        MyList.Add(新MyClass的(,DateTime.Now));
    }    私人无效Delete_Click(对象发件人,Windows.UI.Xaml.RoutedEventArgs E)
    {
        MyList.Remove((MyClass的)AllElementsList.SelectedItem);
    }    私人无效Toggle_Click(对象发件人,RoutedEventArgs E)
    {
        MyClass的oldItem =(MyClass的)AllElementsList.SelectedItem,
            的newitem =新MyClass的(oldItem.Status ==是,否:(oldItem.Status ==否是:),oldItem.Date?);        MYLIST [AllElementsList.SelectedIndex] =的newitem;
    }
}

有了上面,变化永远只能直接向 MYLIST 对象。该列表的状态示于第一个的ListView 在网页的对象(即,最左边的一个)。三种不同的按钮添加被配置为以不同的过滤件。该项目被添加到主列表,但随后三滤的看法会自动进行更新,以反映这些变化,你会看到,在页面上的其他的ListView 对象(每一个都是,增加了被显示在的ListView项下面的按钮)。

希望帮助!



修改

这是评论和一些附加分,我认为可以改善这个答案的用处:


  • 删除每个的ListView项目(即的SelectedItem 在给定的的ListView )很容易做到,只要你还只是从实际 MYLIST 集合中删除;在每个列表中的对象引用是原来的对象,所以即使他们可能在一个特定视图中选择,你可以随时删除 MYLIST 的对象

  • 您可以修改个人 MyClass的对象,但是,如果没有在这个例子中额外的工作,筛选不会改变。即如果MyClass的正确实现绑定功能(无论是依赖属性或INotifyPropertyChanged的),一个项目的属性变化将在屏幕上显示,但不会影响过滤。上面的例子需要一个对象在 MYLIST 与具有新的价值观的不同实例才能被重新过滤进行更换。

I currently have an ObservableCollection named MyList that is binded to the itemsource of on listview. It also adds and removes items from MyList.

What I want is to add items in each listview based on some criteria. More specific, If the property Status is "Yes" the item should go to the first listview MyListview, if it is "No" to go to the second listview MySecondListview and If Status=="" and the property Date which is a DateTime property points today, then it goes to the third listview.

My MainPage code is:

public sealed partial class MainPage : Page
    {
        private ObservableCollection<MyClass> MyList = new ObservableCollection<MyClass>();
        public MainPage()
        {
            this.InitializeComponent();
            DataContext = MyList;
        }
         private void Add_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
        {
            MyList.Add(new MyClass("Yes", new DateTime(2015, 5, 4)));
        }

        private void Delete_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
        {
            MyList.Remove((MyClass)MyListview.SelectedItem);
        }
    }

My XAML for Main Page is:

<Page
    x:Class="App17.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App17"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Viewbox>

        <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" Height="768" Width="1366">
            <Button x:Name="Delete" Content="Delete" HorizontalAlignment="Left" Height="116" Margin="376,89,0,0" VerticalAlignment="Top" Width="224" Click="Delete_Click"/>
            <Button x:Name="Add" Content="Add" HorizontalAlignment="Left" Height="116" Margin="111,89,0,0" VerticalAlignment="Top" Width="214" Click="Add_Click"/>
            <ListView x:Name="MyListview" HorizontalAlignment="Left" Height="497" Margin="71,261,0,0" VerticalAlignment="Top" Width="349" ItemsSource="{Binding}"/>
            <ListView x:Name="MySecondListview" HorizontalAlignment="Left" Height="497" Margin="468,261,0,0" VerticalAlignment="Top" Width="317"/>
            <ListView x:Name="MyThirdListview" HorizontalAlignment="Left" Height="497" Margin="893,261,0,0" VerticalAlignment="Top" Width="317"/>

        </Grid>
    </Viewbox>
</Page>

My Class code is:

class MyClass 
{ 
    public string Status { get; set; } 
    public DateTime Date { get; set; }

    public MyClass(string status, DateTime date) 
    {
        Status = status;
        Date = date; 
    } 
}

解决方案

Ugh. So, I didn't realize this but it turns out that Winrt (i.e. Windows Store apps) does not support filtering in ICollectionView. It seems like every time I turn around, I find another XAML/WPF feature that was inexplicably omitted from Winrt, and this is one of them.

So, while this would have been trivial to accomplish in WPF (just create a CollectionViewSource object, subscribe to the Filter event, and bind to the object's View), this turns out to be a bit more of a hassle in Winrt.

There are already some related articles, including one on Stack Overflow that provide alternatives. For example:

That second one is a very elaborate implementation to support filtering and other operations. It's overkill for your purposes, but you may find in the future you would like to use features it includes.

The first example, while more appropriate in scale to your question, approached the problem in somewhat different way than I would. In particular, it implements a single ObservableCollection<T> subclass that in turn has a single view. This prevents it from being useful for the "one collection, many views" scenario.

So I wrote an ObservableCollection<T> that is in the same vein, but which itself is the view, and references an independent instance of ObservableCollection<T>. You can use as many instances of this class, which I called FilteredObservableCollection<T>, as you need while still maintaining a single source collection. Each view will update itself as needed, according to the filter, when the source collection changes.

<caveat index="0">
In this approach (the original inspiration for my class, as well as my own), the bound view is itself an ObservableCollection<T>. And in particular, this is not a read-only collection. It's very important that any consumers of these "view" objects not try to directly modify the view object, even though they can. They should only ever display the object.

The second link above is better in this respect, as it's implementing an actual ICollectionView interface, which addresses the mutability question. Frankly, it would be better from a code maintenance point of view to do it that way, to make it clearer what object is the real list, and what objects are just the views.

But fact is, this way is a lot simpler and easier to implement. Just be careful using it, and you won't get hurt. :)
</caveat>

<caveat index="1">
The other very important limitation to understand is that this implementation will not update the viewed collection on changes to the filter logic (i.e. in case you pass a Predicate<T> that itself depends on some mutable state somewhere), or on changes to the displayed data (i.e. if a property being checked by the filter is modified in one or more displayed data items).

These limitations could be addressed in a variety of ways, but to do so would significantly increase the complexity of this answer. I would like to try to keep things simple. It's my hope that merely pointing these limitations out is sufficient, to ensure that if you do run into a situation where you need a more reactive view implementation, you're aware of the limitation and know you'll have to extend this solution to support your need.
</caveat>

That class winds up looking like this:

public class FilteredObservableCollection<T> : ObservableCollection<T>
{
    private Predicate<T> _filter;

    public FilteredObservableCollection(ObservableCollection<T> source, Predicate<T> filter)
        : base(source.Where(item => filter(item)))
    {
        source.CollectionChanged += source_CollectionChanged;
        _filter = filter;
    }

    private void _Fill(ObservableCollection<T> source)
    {
        Clear();
        foreach (T item in source)
        {
            if (_filter(item))
            {
                Add(item);
            }
        }
    }

    private int this[T item]
    {
        get
        {
            int foundIndex = -1;
            for (int index = 0; index < Count; index++)
            {
                if (this[index].Equals(item))
                {
                    foundIndex = index;
                    break;
                }
            }
            return foundIndex;
        }
    }

    private void source_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        ObservableCollection<T> source = (ObservableCollection<T>)sender;

        switch (e.Action)
        {
        case NotifyCollectionChangedAction.Add:
            foreach (T item in e.NewItems)
            {
                if (_filter(item))
                {
                    Add(item);
                }
            }
            break;

        case NotifyCollectionChangedAction.Move:
            // Without a lot more work maintaining the view state, it would be just as hard
            // to figure out where the moved item should go, as it would be to just regenerate
            // the whole view. So just do the latter.
            _Fill(source);
            break;

        case NotifyCollectionChangedAction.Remove:
            foreach (T item in e.OldItems)
            {
                // Don't bother looking for the item if it was filtered out
                if (_filter(item))
                {
                    Remove(item);
                }
            }
            break;

        case NotifyCollectionChangedAction.Replace:
            for (int index = 0; index < e.OldItems.Count; index++)
            {
                T item = (T)e.OldItems[index];
                if (_filter(item))
                {
                    int foundIndex = this[item];

                    if (foundIndex == -1)
                    {
                        // i.e. should never happen
                        throw new Exception("internal state failure. object not present, even though it should be.");
                    }

                    T newItem = (T)e.NewItems[index];

                    if (_filter(newItem))
                    {
                        this[foundIndex] = newItem;
                    }
                    else
                    {
                        RemoveAt(foundIndex);
                    }
                }
                else
                {
                    // The item being replaced wasn't in the filtered
                    // set of data. Rather than do the work to figure out
                    // where the new item should go, just repopulate the
                    // whole list. (Same reasoning as for Move event).
                    _Fill(source);
                }
            }
            break;

        case NotifyCollectionChangedAction.Reset:
            _Fill(source);
            break;
        }
    }
}

So, with that helper object implemented, setting up your UI is simple. Just create a new instance of the above class for each view of your data you want, and bind to that instance.

For this example, I reworked your original UI fairly extensively, to clean things up a bit and make it easier to observe what's going on. I added buttons to create items that should appear in each view, and there are now four views: the whole list (where you can select and delete items), and then one each for the three filtering options.

With this approach, the DataContext winds up being this instead of the one list, because we want access to the individual views. The members also need to be changed to public properties, so that the XAML binding engine can find them. This example assumes that they will be initialized once and never changed; if you want the bindings to be updatable, you'll want to make these dependency properties or implement INotifyPropertyChanged in the MainPage class.

I also added a DataTemplate for your class, so that the presentation of each item in each list was useful (i.e. something other than the type name).

With all that, the XAML winds up looking like this:

<Page
    x:Class="TestSO30038588ICollectionView.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:TestSO30038588ICollectionView"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

  <Page.Resources>
    <DataTemplate x:Key="myClassTemplate">
      <StackPanel Orientation="Horizontal">
        <TextBlock Text="{Binding Status}"/>
        <TextBlock Text="{Binding Date}" Margin="20, 0, 0, 0"/>
      </StackPanel>
    </DataTemplate>
  </Page.Resources>
  <Viewbox>
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" Height="768" Width="1366">
      <Grid.ColumnDefinitions>
        <ColumnDefinition/>
        <ColumnDefinition/>
        <ColumnDefinition/>
        <ColumnDefinition/>
      </Grid.ColumnDefinitions>
      <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
        <RowDefinition/>
      </Grid.RowDefinitions>
      <Button x:Name="Delete" Content="Delete"
              HorizontalAlignment="Left" VerticalAlignment="Top"
              Height="116" Width="224"
              Grid.Row="0" Grid.Column="0"
              Click="Delete_Click"/>
      <Button x:Name="Toggle" Content="Toggle Yes/No"
              HorizontalAlignment="Left" VerticalAlignment="Top"
              Height="116" Width="224"
              Grid.Row="1" Grid.Column="0"
              Click="Toggle_Click"/>
      <Button x:Name="AddYes" Content="Add Yes"
              HorizontalAlignment="Left" VerticalAlignment="Top"
              Height="116" Width="214"
              Grid.Row="0" Grid.Column="1"
              Click="AddYes_Click"/>
      <Button x:Name="AddNo" Content="Add No"
              HorizontalAlignment="Left" VerticalAlignment="Top"
              Height="116" Width="214"
              Grid.Row="0" Grid.Column="2"
              Click="AddNo_Click"/>
      <Button x:Name="AddEmpty" Content="Add Empty"
              HorizontalAlignment="Left" VerticalAlignment="Top"
              Height="116" Width="214"
              Grid.Row="0" Grid.Column="3"
              Click="AddEmpty_Click"/>
      <ListView x:Name="AllElementsList"
                ItemTemplate="{StaticResource myClassTemplate}"
                HorizontalAlignment="Left" VerticalAlignment="Top"
                Grid.Row="2" Grid.Column="0"
                ItemsSource="{Binding MyList}"/>
      <ListView x:Name="MyListview"
                ItemTemplate="{StaticResource myClassTemplate}"
                HorizontalAlignment="Left" VerticalAlignment="Top"
                Grid.Row="1" Grid.Column="1" Grid.RowSpan="2"
                ItemsSource="{Binding yesList}"/>
      <ListView x:Name="MySecondListview"
                ItemTemplate="{StaticResource myClassTemplate}"
                HorizontalAlignment="Left" VerticalAlignment="Top"
                Grid.Row="1" Grid.Column="2" Grid.RowSpan="2"
                ItemsSource="{Binding noList}"/>
      <ListView x:Name="MyThirdListview"
                ItemTemplate="{StaticResource myClassTemplate}"
                HorizontalAlignment="Left" VerticalAlignment="Top"
                Grid.Row="1" Grid.Column="3" Grid.RowSpan="2"
                ItemsSource="{Binding emptyList}"/>
    </Grid>
  </Viewbox>
</Page>

And the MainPage code looks like this:

public sealed partial class MainPage : Page
{
    public ObservableCollection<MyClass> MyList { get; set; }
    public FilteredObservableCollection<MyClass> yesList { get; set; }
    public FilteredObservableCollection<MyClass> noList { get; set; }
    public FilteredObservableCollection<MyClass> emptyList { get; set; }

    public MainPage()
    {
        this.InitializeComponent();

        MyList = new ObservableCollection<MyClass>();
        yesList = new FilteredObservableCollection<MyClass>(MyList, item => item.Status == "Yes");
        noList = new FilteredObservableCollection<MyClass>(MyList, item => item.Status == "No");
        emptyList = new FilteredObservableCollection<MyClass>(MyList, item => item.Status == "" && item.Date.Date == DateTime.Now.Date);

        DataContext = this;
    }

    private void AddYes_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
    {
        MyList.Add(new MyClass("Yes", DateTime.Now));
    }

    private void AddNo_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
    {
        MyList.Add(new MyClass("No", DateTime.Now));
    }

    private void AddEmpty_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
    {
        MyList.Add(new MyClass("", DateTime.Now));
    }

    private void Delete_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
    {
        MyList.Remove((MyClass)AllElementsList.SelectedItem);
    }

    private void Toggle_Click(object sender, RoutedEventArgs e)
    {
        MyClass oldItem = (MyClass)AllElementsList.SelectedItem,
            newItem = new MyClass(oldItem.Status == "Yes" ? "No" : (oldItem.Status == "No" ? "Yes" : ""), oldItem.Date);

        MyList[AllElementsList.SelectedIndex] = newItem;
    }
}

With the above, changes are only ever made directly to the MyList object. The state of this list is shown in the first ListView object on the page (i.e. the left-most one). The three different buttons add items that are configured to be filtered differently. The items are added to the main list, but then the three filtered views update themselves automatically to reflect those changes, and you will see that in the other ListView objects on the page (each one is below the button that adds an item that is displayed in that ListView).

Hope that helps!


EDIT:

Some additional points that were in comments and which I think could improve the usefulness of this answer:

  • Deleting items from each ListView (i.e. the SelectedItem in a given ListView) can be done easily, as long as you still just delete from the actual MyList collection; the object references in each list are your original objects, so even though they may be selected in one particular view, you can always delete that object from MyList
  • You can modify the individual MyClass objects but, without additional work in this example, the filtering won't change. I.e. if MyClass correctly implements binding features (either dependency properties or INotifyPropertyChanged), changes to an item's properties will be shown on-screen, but won't affect filtering. The above example requires an object to be replaced in MyList with a different instance having the new values for it to be refiltered.

这篇关于的ObservableCollection 1 3的列表视图取决于某些属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆