简体   繁体   中英

Why is my ItemsControl not render ILookup<T,V> when set as ItemsSource

I have a class with a property Errors defined as:

public MultiLookup<string, Exception> Errors { get; private set; } 

MultiLookup is of type ILookup as defined:

public class MultiLookup<TKey, TValue,TCollection> : ILookup<TKey, TValue>

This is bound to the ItemsSource property of an ItemsControl defined in XAML:

<ItemsControl ItemsSource="{Binding Path=Errors}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <StackPanel>
                <Label Content="{Binding Path=Key}" />
            </StackPanel>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

No items are rendered

Inspecting the live property explorer one can see that there are no items in the control being rendered. The stack panel should have 4 items in it.

However there are 4 keys in the lookup table as shown in the live property explorer within Visual Studio, during a debug session.

Why do the 4 items not get rendered?

There are two reasons here.

  1. My MultiLookup does not implement INotifyCollectionChanged.
  2. Even if you manually call Items.Refresh on the ItemsControl the binding does not update the ItemsControl.

The solution is simple. Create an immutable version of the collection that I update on every change.

    private readonly MultiLookup<string, Exception, List<Exception>>
             _Errors;

    [Reactive]public ILookup<string, Exception> Errors 
            { get; private set; } 

where _Errors is the mutable version for internal handling and Errors is the immutable version which raises INPC events. I'm using ReactiveUI.Fody to implement INPC

On every change to the mutable version I just call

// Create a new immutable lookup on every error change.
Errors = _Errors
            .SelectMany(p => p.Select(i => new {p.Key, i}))
            .ToLookup(o => o.Key, o => o.i);

It now updates the ItemsControl correctly.

I could also have implemented MultiLookup with INotifyCollectionChanged to get a similar effect. Given that the expected size of this collection will always be very small ( less than 10 ) there is little overhead in generating a new copy each time. INotifyCollectionChanged` is also quite complex to get working correctly for a data structure like a lookup.

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