UWP将IEnumerable转换为ObservableCollection(x:Bind)

时间:2017-03-15 18:29:28

标签: c# listview uwp observablecollection xbind

好的,我有一个IEnumerable集合,我x:Bind加入ListView

当应用程序正在运行时,我希望每当此IEnumerable列表发生更改时,我的listview也会更新。即使使用INotifyPropertyChanged也不是这种情况,因此我决定将IEnumerable转换为ObservableCollection

我发现存在的演员是:

myCollection = new ObservableCollection<object>(the_list);

这在另一个问题上可以正常工作,但在我的情况下我是x:将它绑定到listview并且每次使用上面的代码运行方法时都会创建一个新引用并且绑定不会工作(它不起作用)。那是对的吗 ?如果是,我该如何解决这个问题?如果没有,我做错了什么?谢谢。

目前我的代码如下:

public ObservableCollection<IMessage> MessageList;

private async Task SetMessages()
{
    MessageList = new ObservableCollection<IMessage>(await channel.GetMessagesAsync(NumOfMessages).Flatten());
}

为我工作的是什么:

完全由于MarianDolinský的回答,现在一切正常。我提供一些代码以使其更清楚我所做的是:

class ChatViewModel : INotifyPropertyChanged
{
    //Number of messages to have in list at once.
    private int NumOfMessages = 20;

    //Called when a user clicks on a channel.
    public async Task SelectChannel(object sender, ItemClickEventArgs e)
    {
        //Set the channel to clicked item
        channel = (SocketTextChannel)e.ClickedItem;
        //Receive the messages in the list.
        IEnumerable<IMessage> data = await channel.GetMessagesAsync(NumOfMessages).Flatten();
        //Clear the observablecollection from any possible previous messages (if for example you select another channel).
        messageList.Clear();
        //Loop and add all messages to the observablecollection
        foreach (var item in data)
        {
            messageList.Add(item);
        }
    }

    //The event handler when a message is received.
    private async Task Message_Received(SocketMessage arg)
    {
        //Calls to add message only if the message received is of interest.
        if (arg.Channel == channel)
        {
            //Sets the thread equal to the UI thread.
            await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
             {
                //Adds the new message, removes the oldest to keep always 20.
                 messageList.Add(arg);
                 messageList.Remove(messageList[0]);
             });
        }
    }

    private ObservableCollection<IMessage> messageList = new ObservableCollection<IMessage>();

    public ObservableCollection<IMessage> MessageList
    {
        get
        {
            return messageList;
        }
    }
}

以下是XAML中的代码:

<Page.DataContext>
    <vm:ChatViewModel x:Name="ChatViewModel"/>
</Page.DataContext>

                    <ListView VerticalContentAlignment="Bottom" ItemsSource="{x:Bind ChatViewModel.MessageList, Mode=OneWay}" SelectionMode="None" ItemTemplate="{StaticResource MessageListDataTemplate}">
                        <ListView.ItemContainerStyle>
                            <Style TargetType="ListViewItem">
                                <Setter Property="HorizontalContentAlignment" Value="Stretch" />
                                <Setter Property="Margin" Value="0,0,5,5"/>
                            </Style>
                        </ListView.ItemContainerStyle>
                    </ListView>

再次感谢您的帮助:)

1 个答案:

答案 0 :(得分:2)

由于colg的工作原理,它未更新 - 它仅通知集合内的更改,但是当您在ObservableCollection方法中分配MessageList时,您和#39;重新创建SetMessages的新实例,ObservableCollection指向ListView.Source的原始绑定实例。

另外,我发现ObservableCollection不是属性,而是字段。字段不适用于绑定。

如何更新MessageList

,您有四种选择

1)您可以将现有ListView与新数据同步:

MessageList


2)如果您未在其他任何地方使用private async Task SetMessages() { IEnumerable newData = await channel.GetMessagesAsync(20).Flatten(); // Assuming MessageList is not null here you will sync newData with MessageList } 集合,则可以直接从代码设置MessageList ItemsSource属性:

ListView


3)由于您使用的是private async Task SetMessages() { YourListView.ItemsSource = await channel.GetMessagesAsync(20).Flatten(); } 表达式,因此每次要刷新页面上的任何绑定时,都可以调用x:Bind方法:

Bindings.Update();


4)您可以在页面上实施private async Task SetMessages() { MessageList = new ObservableCollection<IMessage>(await channel.GetMessagesAsync(20).Flatten()); Bindings.Update(); } 或为INotifyPropertyChanged创建DependencyProperty,然后将其与设置为MessageList的{​​{1}}绑定:

Mode

就我个人而言,我不推荐第四种选择。最好的选择是同步数据,因为OneWay会自动动画添加和删除ListViewItems。

修改

我认为问题出在以下两个方面:

<ListView ItemsSource="{x:Bind MessageList, Mode=OneWay}">

因为在集合的末尾添加了新项目,所以您要删除上次添加的项目。要删除最旧的项目,您应使用ListView删除第一个位置的项目。