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

UWP Convert IEnumerable to ObservableCollection (x:Bind)

好的,所以我有一个 IEnumerable 集合,我 x:Bind 变成了 ListView

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

我发现存在的演员表是:

myCollection = new ObservableCollection<object>(the_list);

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

目前我的代码如下所示:

public ObservableCollection<IMessage> MessageList;

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

对我有用的:

完全感谢 Marian Dolinský 的回答,现在一切正常。我展示了一些我的代码以使其更清楚我所做的是:

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>

再次感谢您的帮助:)

由于 ObservableCollection 的工作方式,它没有更新 - 它仅通知集合内部的更改,但是当您在 SetMessages 方法中分配 MessageList 时,您创建 ObservableCollection 的新实例并且 ListView.Source 指向 ObservableCollection 的原始绑定实例。

此外,我看到 MessageList 不是 属性,而是字段。字段不适用于绑定。

如何实现 ListView 的更新有四种选择:

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

private async Task SetMessages()
{
    IEnumerable newData = await channel.GetMessagesAsync(20).Flatten();

    // Assuming MessageList is not null here you will sync newData with MessageList
}


2) 如果您没有在其他任何地方使用 MessageList 集合,您可以直接从代码中设置 ListViewItemsSource 属性:

private async Task SetMessages()
{
     YourListView.ItemsSource = await channel.GetMessagesAsync(20).Flatten();
}


3) 由于您使用的是 x:Bind 表达式,因此您可以在每次要刷新页面上的任何绑定时调用 Bindings.Update(); 方法:

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


4) 您可以在页面上实现 INotifyPropertyChanged 或为 MessageList 创建 DependencyProperty 然后将其绑定 Mode 设置为 OneWay:

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

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

编辑:

我认为问题出在这两行:

messageList.Add(arg);
messageList.Remove(messageList[NumOfMessages - 1]);

由于新项目是在集合的末尾添加的,因此您将删除上次添加的项目。要删除最旧的项目,您应该使用 messageList.RemoveAt(0); 删除第一个位置的项目。