简体   繁体   中英

How can I bind to a property value within a an object in a grouped list

First off, thankyou for the solution to my previous question here

That solution works very well, however, i'm struggling to bind the change of one of the properties. I have the BackgroundColour binding well when the UI loads with the following code: UI View

<StackLayout x:Name="stlShippingOrders" Spacing="5" Padding="0,0,0,5" >
        <CollectionView Margin="0,-6,0,0" IsGrouped="True" ItemsSource="{Binding 
ShippingItems}">
            <CollectionView.GroupHeaderTemplate>
                <DataTemplate>
                    <StackLayout Padding="5,-5,5,-5" Orientation="Horizontal" 
BackgroundColor="LightBlue" HeightRequest="45">
                        <Label Text="{Binding Shipment.OrderCode}" 
VerticalOptions="Center"/>
                        <Label Text="{Binding Shipment.CustomerName}" 
VerticalOptions="Center"/>
                        <Label Text="{Binding Shipment.DeliveryDate}" 
HorizontalOptions="EndAndExpand" VerticalOptions="Center" />
                    </StackLayout>
                </DataTemplate>
            </CollectionView.GroupHeaderTemplate>
            <CollectionView.ItemTemplate>
                <DataTemplate>
                    <Label Padding="5,2,5,2" Text="{Binding ItemDescription}" 
BackgroundColor="{Binding BackgroundColour}"/>
                </DataTemplate>
            </CollectionView.ItemTemplate>
        </CollectionView>
    </StackLayout>

ShippingItem Model (with added BacgroundColour property)

 public class ShippingItem
{
    public String ShippingItemId { get; set; }
    public string ShippingItemScanCode { get; set; }
    public string ItemDescription { get; set; }
    public string ShippingOrderId { get; set; }
    public bool IsLoaded { get; set; }

    // Default set to transparent #00FFFFFF
    public string BackgroundColour { get; set; }  = "#00FFFFFF";

}

Class for grouping

public class ShippingItemGroup : ObservableCollection<ShippingItem>
{
    public ShippingOrder Shipment { get; private set; }

    public ShippingItemGroup(ShippingOrder shipment, ObservableCollection<ShippingItem> 
shippingItems) : base(shippingItems)
    {
        Shipment = shipment;
    }
}

ViewModel code that creates the group list and binds correctly

                        public ObservableCollection<ShippingItemGroup> ShippingItems { 
get; private set; } = new ObservableCollection<ShippingItemGroup>();
                    foreach (var item in thisShipment.ShippingOrders)
                    {
                        ShippingItems.Add(new ShippingItemGroup(item, 
item.ShippingItems));
                    }

ViewModel code that updates the list object when it is loaded. This is the bit i'm having trouble with, the shippingItem.BackgroundColour = "FFA533" changes the collection but doesn't update the UI.

foreach (ShippingItemGroup shippingItemGroup in ShippingItems)
                    {
                        foreach(ShippingItem shippingItem in 
shippingItemGroup.Shipment.ShippingItems)
                        {
                            if(shippingItem.ShippingItemScanCode == scanCode)
                            {
                                shippingItem.IsLoaded = true;
                                shippingItem.BackgroundColour = "FFA533";
                                IsShipmentHeaderVisible = true;
                                IsShippingOrdersVisible = true;
                                IsErrorMessageVisible = false;
                                ScanCode = "";
                            }
                        }
                    }

As Jason mentioned in the comments, you need to implement INotifyPropertyChanged. This is the way I've done it for other projects. This is adapted from how MVVMCross does it.

First, create a base class where the INotifyPropertyChanged logic is setup:

public class ModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
    {
        if (EqualityComparer<T>.Default.Equals(storage, value))
        {
            return false;
        }

        storage = value;
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        return true;
    }
}

This will handle setting the value and firing the PropertyChanged event.

Next, have whatever model you need inherit from this base class. In this, it's your ShippingItem class:

public class ShippingItem : ModelBase
{
    public int Id { get; set; }
    public int ShippingOrderId { get; set; }
    public string ItemDescription { get; set; }
    public bool IsLoaded { get; set; }

    private string backgroundColor;
    public string BackgroundColor
    {
        get => backgroundColor;
        set => SetProperty(ref backgroundColor, value);
    }
}

Note the addition of the private backgroundColor field, and the custom setter that calls the SetProperty in the base class.

This will handle the updates for you.

I modified the code from the previous answer just as a proof of concept. This will update the colors every 1.5 seconds:

public MainPage()
{
    InitializeComponent();

    var shipment = new Shipment();

    foreach (var item in shipment.ShippingOrders)
    {
        ShippingItems.Add(new ShippingItemGroup(item, item.ShippingItems));
    }

    BindingContext = this;

    var rnd = new Random();
    Task.Run(async () =>
    {
        while (true)
        {
            await Task.Delay(1500);
            foreach (var shippingItemGroup in ShippingItems)
            {
                foreach (var shippingItem in shippingItemGroup)
                {
                   shippingItem.BackgroundColor = Color.FromRgb(rnd.Next(256), rnd.Next(256), rnd.Next(256)).ToHex();
                }
            }
       }
    });
}

public ObservableCollection<ShippingItemGroup> ShippingItems { get; private set; } = new ObservableCollection<ShippingItemGroup>();

在此处输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM