Обновление представления с новым ObservableCollection вызывает дубликаты в макете - PullRequest
0 голосов
/ 17 декабря 2018

У меня есть простое приложение, которое отображает контент из ObservableCollection of Labels в зависимости от того, какая кнопка в ObservableCollection кнопок нажата.Нажатием кнопки «Обновить» я хочу заменить метки и кнопки и отображать их.Для этого у меня есть привязки к соответствующим ObservableCollections, и я делаю .Clear () для каждой из коллекций перед обновлением.ObservableCollections корректно обновляется, но элементы, отображаемые на экране, являются как старыми, так и новыми элементами.Кажется, что мой макет не обновляется сам, скорее добавьте новый макет рядом с обновленными элементами.Следующие снимки экрана иллюстрируют проблему:

при нагрузке:

enter image description here

при обновлении:

enter image description here

Как остановить отображение старых элементов (первые кнопки 1 и 2, начальный элемент 1)?

MainPage.xaml:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
    x:Class="TestApp.MainPage"
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:local="clr-namespace:TestApp">

    <StackLayout>
        <Button Command="{Binding LoadCommand}" Text="Load" />
        <Button Command="{Binding RefreshCommand}" Text="Refresh" />
        <local:BindableStackLayout
            HorizontalOptions="FillAndExpand"
            Items="{Binding ButtonCollection}"
            Orientation="Horizontal"
            VerticalOptions="Start" />
        <local:BindableStackLayout
            HorizontalOptions="FillAndExpand"
            Items="{Binding ItemCollection}"
            VerticalOptions="FillAndExpand" />
    </StackLayout>
</ContentPage>

MainPage.xaml.cs:

using Xamarin.Forms;

namespace TestApp
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
            this.BindingContext = new MyViewModel();
        }
    }
}

MyViewModel.cs:

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using Xamarin.Forms;

namespace TestApp
{
    class MyViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public ObservableCollection<View> ButtonCollection { get; set; }
        public ObservableCollection<View> ItemCollection { get; set; }
        public Command LoadCommand { get; set; }
        public Command RefreshCommand { get; set; }
        public List<string> ItemList { get; set; }
        public int SelectedItem { get; set; }
        public MyViewModel()
        {
            ButtonCollection = new ObservableCollection<View>();
            ItemCollection = new ObservableCollection<View>();
            LoadCommand = new Command(Load);
            RefreshCommand = new Command(Refresh);
        }

        public void SelectItem(int item)
        {
            SelectedItem = item;
            for (int i = 0; i < ItemList.Count; i++)
            {
                if (item == i)
                {
                    ItemCollection[i].IsVisible = true;
                    ButtonCollection[i].BackgroundColor = Color.Yellow;
                }
                else
                {
                    ItemCollection[i].IsVisible = false;
                    ButtonCollection[i].BackgroundColor = Color.LightGray;
                }
            }
        }

        public void Load()
        {
            ItemList = new List<string> { "Initial item 1", "Initial item 2" };
            for (int i = 0; i < ItemList.Count; i++)
            {
                int copy = i;
                ButtonCollection.Add(new Button { Command = new Command(() => { SelectItem(copy); }), FontSize = 32, Text = (i + 1).ToString(), HeightRequest = 100, HorizontalOptions = LayoutOptions.FillAndExpand });
                ItemCollection.Add(new Label { Text = ItemList[i] });
            }
            SelectItem(0);
        }

        public void Refresh()
        {
            ItemList = new List<string> { "Updated item 1", "Updated item 2", "Updated item 3" };
            ItemCollection.Clear();
            ButtonCollection.Clear();
            for (int i = 0; i < ItemList.Count; i++)
            {
                int copy = i;
                ButtonCollection.Add(new Button { Command = new Command(() => { SelectItem(copy); }), FontSize = 32, Text = (i + 1).ToString(), HeightRequest = 100, HorizontalOptions = LayoutOptions.FillAndExpand });
                ItemCollection.Add(new Label { Text = ItemList[i] });
            }


      System.Diagnostics.Debug.WriteLine(ItemCollection.Count);
        SelectItem(0);
    }

    protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

}

BindableStackLayout.cs

using Xamarin.Forms;
using System.Collections.Specialized;
using System.Collections.ObjectModel;

namespace TestApp
{
    class BindableStackLayout : StackLayout
    {
        public static readonly BindableProperty ItemsProperty =
            BindableProperty.Create(nameof(Items), typeof(ObservableCollection<View>), typeof(BindableStackLayout), null,
                propertyChanged: (b, o, n) =>
                {
                    (n as ObservableCollection<View>).CollectionChanged += (coll, arg) =>
                    {
                        switch (arg.Action)
                        {
                            case NotifyCollectionChangedAction.Add:
                                foreach (var v in arg.NewItems)
                                    (b as BindableStackLayout).Children.Add((View)v);
                                break;
                            case NotifyCollectionChangedAction.Remove:
                                foreach (var v in arg.NewItems)
                                    (b as BindableStackLayout).Children.Remove((View)v);
                                break;
                        }
                    };
                });

        public ObservableCollection<View> Items
        {
            get { return (ObservableCollection<View>)GetValue(ItemsProperty); }
            set { SetValue(ItemsProperty, value); }
        }
    }
}

Ответы [ 3 ]

0 голосов
/ 17 декабря 2018

Вызов Clear() на ObservableCollection<T> не вызывает несколько CollectionChanged событий с Action на NotifyCollectionChangedAction.Remove.

Попробуйте обработать NotifyCollectionChangedAction.Reset в вашем классе BindableStackLayout или удалите элементы по одному в вашей модели представления:

public void Refresh()
{
    for (int i = ItemCollection.Count - 1; i >= 0; i--)
        ItemCollection.RemoveAt(i);
    for (int i = ButtonCollection.Count - 1; i >= 0; i--)
        ButtonCollection.RemoveAt(i);

    ItemList = new List<string> { "Updated item 1", "Updated item 2", "Updated item 3" };
    for (int i = 0; i < ItemList.Count; i++)
    {
        int copy = i;
        ButtonCollection.Add(new Button { Command = new Command(() => { SelectItem(copy); }), FontSize = 32, Text = (i + 1).ToString(), HeightRequest = 100, HorizontalOptions = LayoutOptions.FillAndExpand });
        ItemCollection.Add(new Label { Text = ItemList[i] });
    }

    System.Diagnostics.Debug.WriteLine(ItemCollection.Count);
    SelectItem(0);
}
0 голосов
/ 18 декабря 2018

После очистки просто заново инициализируйте коллекции, как показано ниже,

 ItemCollection = new ObservableCollection<View>();
 ButtonCollection = new ObservableCollection<View>();
0 голосов
/ 17 декабря 2018

Есть отдельное действие для очистки списка.Так что это, вероятно, должно работать:

switch (arg.Action)
{
    case NotifyCollectionChangedAction.Add:
        foreach (var v in arg.NewItems)
            (b as BindableStackLayout).Children.Add((View)v);
        break;
    case NotifyCollectionChangedAction.Remove:
        foreach (var v in arg.NewItems)
            (b as BindableStackLayout).Children.Remove((View)v);
        break;
    case NotifyCollectionChangedAction.Reset:
        (b as BindableStackLayout).Children.Clear();
        break;
}

https://docs.microsoft.com/en-us/dotnet/api/system.collections.specialized.notifycollectionchangedaction?view=netcore-2.0

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...