Проблема привязки данных в Xamarin.Forms CollectionView - PullRequest
0 голосов
/ 25 мая 2020

Мне не удается найти хороший способ изменить свойство объекта внутри списка с помощью CollectionView в Xamarin.Forms.

Ниже мой код (только соответствующий код для удобства чтения).

У меня есть список, который я привязываю к CollectionView. Каждая запись в обзоре коллекции содержит метку с числом и двумя кнопками для увеличения и уменьшения этого числа на 1.

Обратите внимание, что приведенный ниже код работает нормально. Однако меня не устраивает реализация INotifyPropertyChanged в моей модели, которая должна быть простым DTO. Я бы хотел удалить этот интерфейс из моей модели вместе с OnPropertyChanged. Когда я это делаю, метка с номером больше не меняется, когда я нажимаю кнопку.

Итак, я должен внести эти изменения в ViewModel, но я не мог понять, как это сделать. Каким будет подходящий способ реализовать это в модели представления, чтобы я мог поддерживать чистоту своей модели с помощью только простого свойства?

Обратите внимание, что BaseViewModel уже реализует интерфейс INotifyPropertyChanged.

enter image description here

Xaml:

<CollectionView ItemsSource="{Binding MyList}" SelectionMode="Single">
    <CollectionView.ItemTemplate>
        <DataTemplate>
            <StackLayout Orientation="Horizontal">
                <Button Text="-"
                        Command="{Binding Source={x:Reference MyPage}, Path=BindingContext.QuantityMinusCommand}"
                        CommandParameter="{Binding .}" />
                <Label Text="{Binding Quantity, Mode=TwoWay}" />
                <Button Text="+"
                        Command="{Binding Source={x:Reference MyPage}, Path=BindingContext.QuantityPlusCommand}"
                        CommandParameter="{Binding .}" />
            </StackLayout>
        </DataTemplate>
    </CollectionView.ItemTemplate>
</CollectionView>

Модель просмотра:

public class CollectionViewModel : BaseViewModel
{
    private List<MyObject> _myList = new List<MyObject>();

    public ICommand QuantityMinusCommand { get; }
    public ICommand QuantityPlusCommand { get; }

    public CollectionViewModel()
    {
        QuantityMinusCommand = new Command(OnQuantityMinusCommand);
        QuantityPlusCommand = new Command(OnQuantityPlusCommand);
    }

    public List<MyObject> MyList
    {
        get => _myList;
        set
        {
            _myList = value;
            OnPropertyChanged("MyList");
        }
    }

    private void OnQuantityMinusCommand(object o)
    {
        var myObject = (MyObject)o;
        myObject.Quantity = --myObject.Quantity;
    }


    private void OnQuantityPlusCommand(object o)
    {
        var myObject = (MyObject)o;
        myObject.Quantity = ++myObject.Quantity;
    }
}

Модель:

public class MyObject : System.ComponentModel.INotifyPropertyChanged
{
    private int _quantity;
    public int Quantity
    {
        get => _quantity;
        set
        {
            _quantity = value;
            OnPropertyChanged("Quantity");
        }
    }


    public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = "")
    {
        var changed = PropertyChanged;
        if (changed == null)
            return;

        changed.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
    }
}

1 Ответ

0 голосов
/ 25 мая 2020

Ваша BaseViewModel может унаследовать INotifyPropertyChanged. И тогда ваша модель может быть простым DTO.

public class BaseViewModel : ObservableObject
{
    public BaseViewModel()
    {

    }

    bool isBusy = false;
    public bool IsBusy
    {
        get { return isBusy; }
        set { SetProperty(ref isBusy, value); }
    }
}

И ObservableObject

/// <summary>
/// Observable object with INotifyPropertyChanged implemented
/// </summary>
public class ObservableObject : INotifyPropertyChanged
{
    protected bool SetProperty<T>(ref T backingStore, T value,
        [CallerMemberName]string propertyName = "",
        Action onChanged = null)
    {
        if (EqualityComparer<T>.Default.Equals(backingStore, value))
            return false;

        backingStore = value;
        onChanged?.Invoke();
        OnPropertyChanged(propertyName);
        return true;
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
    {
        var changed = PropertyChanged;
        if (changed == null)
            return;

        changed.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

И модель может быть такой:

public class MyObject
{
    public int Quantity { get; set; }
}

Viewmodel :

public class CollectionViewModel : BaseViewModel
{
    // ...
}
...