UWP конвертировать IEnumerable в ObservableCollection (x:Bind)

Итак, у меня есть IEnumerable Коллекция, которую я x:Bind в ListView,

В то время как приложение работает, я хочу всякий раз, когда это IEnumerable список изменений, мой listview быть обновленным также. Это не так даже при использовании INotifyPropertyChangedпоэтому я решил перейти к преобразованию IEnumerable для ObservableCollection,

Я узнал, что актерский состав, который существует:

myCollection = new ObservableCollection<object>(the_list);

Это будет работать нормально в другой проблеме, но в моем случае я х: привязать это к listview и каждый раз, когда я запускаю метод с приведенным выше кодом, создается новая ссылка, и привязка не будет работать (она не работает). Это верно? Если да, как я могу обойти это? Если нет, что я делаю не так? Спасибо.

В настоящее время мой код выглядит так:

public ObservableCollection<IMessage> MessageList;

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

Что сработало для меня:

Только благодаря ответу Мариана Долинского все работает. Я представляю некоторые из своего кода, чтобы сделать его более понятным. Я сделал следующее:

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 ответ

Решение

Это не обновляется из-за того, как ObservableCollection работает - он уведомляет только об изменениях внутри коллекции, но при назначении MessageList в вашем SetMessages метод, вы создаете новый экземпляр 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 Коллекция где-либо еще, вы можете установить ItemsSource собственностью ListView прямо из кода:

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 на странице или создать DependencyProperty для MessageList а затем связать его с Mode установлен в OneWay:

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

Лично я бы не рекомендовал четвертый вариант. Лучшим вариантом будет синхронизировать данные, так как ListView автоматически оживляет добавление и удаление ListViewItems.

РЕДАКТИРОВАТЬ:

Я думаю, что проблема в этих двух строках:

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

так как новые элементы добавляются в конце коллекции, поэтому вы удаляете элемент, добавленный в прошлый раз. Для удаления самого старого элемента, вы должны использовать messageList.RemoveAt(0); убрать предмет на первой позиции.

Другие вопросы по тегам