Словарь внутри DataTemplate не обновляет интерфейс даже после реализации INotifyPropertyChanged - PullRequest
0 голосов
/ 08 января 2020

У меня есть словарь, который я заполняю, перебирая другой словарь. В какой-то момент команда нажатия кнопки обновляет значение одного из ключей. Проблема в том, что он никогда не обновляет интерфейс с обновленным значением. Но когда я сохраняю точку останова, я вижу ценность обновлений словаря. Пожалуйста, помогите.

public abstract class BindableBase : INotifyPropertyChanged
{
    protected bool Set<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
    {
        if (Equals(storage, value))
        {
            return false;
        }
        storage = value;
        RaisePropertyChanged(propertyName);
        return true;
    }

    protected virtual void RaisePropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

ViewModel:

public class VM
{
    public ICommand HomingSectionAcceptButtonCommand { get; set; }

    private Dictionary<EnumLocalizer<HomingLocationEnums>,string> _homingItems;
    public Dictionary<EnumLocalizer<HomingLocationEnums>, string> HomingItems
    {
        get => _homingItems;
        set
        {
            Set(ref _homingItems, value);
        }
    }

    public VM()
    {
        foreach (var item in _readOrWriteHomingDataHelper.HomingConfiguration)
        {
            HomingItems.Add(new EnumLocalizer<HomingLocationEnums>() { Value = (HomingLocationEnums)Enum.Parse(typeof(HomingLocationEnums), item.Key) }, item.Value);
        }

        HomingSectionAcceptButtonCommand = new RelayCommand<EnumLocalizer<HomingLocationEnums> >(UpdateOffsetsFromDataBase);
    }

    private async void UpdateOffsetsFromDataBase(EnumLocalizer<HomingLocationEnums> homingLocation)
    {
        if (HomingItems.ContainsKey(homingLocation))
        {
            //UI doesn't update the value with ABC
            HomingItems[homingLocation] = "ABC";
        }
    }
}

Вот мое перечисление (что не важно)

public enum HomingLocationEnums
{
    BarCodeScanning = 0,
    Aspiration,
    Framing,
    LABHomeOrFrame,
    LeftScan,
    RightScan,
    LeftAspiration,
    RightAspiration,
    LeftFraming,
    RightFraming
}

Xaml:

<DataTemplate x:Key="HomingTemplate">

    <ListView Grid.Row="1" Grid.Column="1" 
                x:Name="lstHomingItemsTemplate"
                HorizontalAlignment="Stretch" 
                VerticalAlignment="Stretch" 
                ItemsSource="{Binding HomingItems}" Margin="0,20" 
                SelectionMode="None">
        <ListView.ItemTemplate>
            <DataTemplate>
                <Grid HorizontalAlignment="Stretch">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="180"/>
                        <ColumnDefinition Width="180"/>
                        <ColumnDefinition Width="180"/>
                    </Grid.ColumnDefinitions>
                    <TextBlock Grid.Column="0" Text="{Binding Key}" FontSize="{StaticResource FontSizeMedium}" TextWrapping="Wrap"/>
                    <TextBlock Grid.Column="1"  Text="{Binding Value}" FontSize="{StaticResource FontSizeMedium}" TextWrapping="Wrap"/>
                    <Button Grid.Column="2" Margin="20,0,0,0" 
                            Command="{Binding Path=DataContext.HomingSectionAcceptButtonCommand,ElementName=lstHomingItemsTemplate}"
                            CommandParameter="{Binding Key}">
                        <Button.Content>
                            <SymbolIcon Symbol="Accept" 
                        HorizontalAlignment="Center" 
                        VerticalAlignment="Stretch"/>
                        </Button.Content>
                    </Button>
                </Grid>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</Grid>

Ответы [ 2 ]

0 голосов
/ 09 января 2020

Хотя я принял ответ, это то, что в итоге сработало для меня ObservableDictionary. В случае, если это кому-то поможет, вот весь код. Вызовите этот код, создав экземпляр класса ObservablePairCollection извне. Синтаксически такой же как Dictionary.

public class ObservablePairCollection<TKey, TValue> : ObservableCollection<Pair<TKey, TValue> >
{
    public ObservablePairCollection()
        : base()
    {
    }

    public ObservablePairCollection(IEnumerable<Pair<TKey, TValue> > enumerable)
        : base(enumerable)
    {
    }

    public ObservablePairCollection(List<Pair<TKey, TValue> > list)
        : base(list)
    {
    }

    public ObservablePairCollection(IDictionary<TKey, TValue> dictionary)
    {
        foreach (var kv in dictionary)
        {
            Add(new Pair<TKey, TValue>(kv));
        }
    }

    public void Add(TKey key, TValue value)
    {
        Add(new Pair<TKey, TValue>(key, value));
    }
}

public class Pair<TKey, TValue> : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected TKey _key;
    protected TValue _value;

    public TKey Key
    {
        get { return _key; }
        set
        {
            if (
                (_key == null && value != null)
                || (_key != null && value == null)
                || !_key.Equals(value))
            {
                _key = value;
                NotifyPropertyChanged("Key");
            }
        }
    }

    public TValue Value
    {
        get { return _value; }
        set
        {
            if (
                (_value == null && value != null)
                || (_value != null && value == null)
                || (_value != null && !_value.Equals(value)))
            {
                _value = value;
                NotifyPropertyChanged("Value");
            }
        }
    }

    public Pair()
    {
    }

    public Pair(TKey key, TValue value)
    {
        Key = key;
        Value = value;
    }

    public Pair(KeyValuePair<TKey, TValue> kv)
    {
        Key = kv.Key;
        Value = kv.Value;
    }

    protected void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
0 голосов
/ 08 января 2020

Dictionary не реализует INotifyCollectionChanged (в отличие от ObservableCollection). Поэтому добавление / удаление / перемещение элементов коллекции не будет обновлять привязку. Если вы хотите остаться с Dictionary в качестве источника привязки, вы должны поднять PropertyChanged:

foreach (var item in _readOrWriteHomingDataHelper.HomingConfiguration)
{
  HomingItems.Add(new EnumLocalizer<HomingLocationEnums>() { Value = (HomingLocationEnums)Enum.Parse(typeof(HomingLocationEnums), item.Key) }, item.Value);
}

RaisePropertyChanged(nameof(this.HomingItems));

В качестве альтернативы используйте ObservableCollection в качестве источника привязки для ListView. Вы можете создать тип модели данных, который объединяет ключ и значение как атрибуты класса (свойства) для последующей привязки. Повышение PropertyChanged каждый раз, когда Dictionary был изменен, может привести к плохой производительности и другим побочным эффектам, особенно в больших коллекциях.

...