Проблемы с {RelativeSource PreviousData} при удалении элементов коллекции - PullRequest
8 голосов
/ 28 июля 2011

Я использую следующий (упрощенный) код для отображения элемента во всех элементах ItemsControl, кроме первого:

<TheElement Visibility="{Binding RelativeSource={RelativeSource PreviousData},
                                 Converter={StaticResource NullToVisibility}}/>

NullToVisibility - это простой преобразователь, который возвращает Visibility.Hidden, если источник нулевой, Visibility.Visible в противном случае.

Теперь, это прекрасно работает при первоначальном связывании представления или добавлении элементов в список (ObservableCollection), но элемент не становится невидимым для второго элемента при удалении первого .

Есть идеи, как это исправить?

Ответы [ 3 ]

7 голосов
/ 29 июля 2011

Если бы из предыдущего ответа был какой-то потраченный впустую код, можно использовать его здесь:

Ключ должен обновить источник просмотра, например, :

CollectionViewSource.GetDefaultView(this.Categories).Refresh();

enter image description here

Полный пример источника ниже. Удалить первый элемент удаляет первый элемент и обновляет представление:

RelativeSourceTest.xaml

<UserControl x:Class="WpfApplication1.RelativeSourceTest"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:PersonTests="clr-namespace:WpfApplication1" mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <UserControl.Resources>
        <PersonTests:NullToVisibilityConvertor x:Key="NullToVisibility"/>
    </UserControl.Resources>
    <Grid>
        <StackPanel Background="White">
            <Button Content="Remove First Item" Click="Button_Click"/>
            <ListBox ItemsSource="{Binding Categories}">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <CheckBox IsChecked="{Binding Checked, Mode=TwoWay}" >
                            <StackPanel>
                                <TextBlock Text="{Binding CategoryName}"/>
                                <TextBlock Text="Not The First" 
                                    Visibility="{Binding RelativeSource={RelativeSource PreviousData},
                                        Converter={StaticResource NullToVisibility}}"/>
                            </StackPanel>
                        </CheckBox>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
        </StackPanel>
    </Grid>
</UserControl>

RelativeSourceTest.xaml.cs

using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;

namespace WpfApplication1
{
    public partial class RelativeSourceTest : UserControl
    {
        public ObservableCollection<Category> Categories { get; set; }

        public RelativeSourceTest()
        {
            InitializeComponent();
            this.Categories = new ObservableCollection<Category>()
                                {
                                    new Category() {CategoryName = "Category 1"},
                                    new Category() {CategoryName = "Category 2"},
                                    new Category() {CategoryName = "Category 3"},
                                    new Category() {CategoryName = "Category 4"}
                                };
            this.DataContext = this;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            this.Categories.RemoveAt(0);
            CollectionViewSource.GetDefaultView(this.Categories).Refresh();
        }
    }
}

Category.cs

using System.ComponentModel;

namespace WpfApplication1
{
    public class Category : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private bool _checked;
        public bool Checked
        {
            get { return _checked; }
            set
            {
                if (_checked != value)
                {
                    _checked = value;
                    SendPropertyChanged("Checked");
                }
            }
        }

        private string _categoryName;
        public string CategoryName
        {
            get { return _categoryName; }
            set
            {
                if (_categoryName != value)
                {
                    _categoryName = value;
                    SendPropertyChanged("CategoryName");
                }
            }
        }

        public virtual void SendPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}
1 голос
/ 23 мая 2017

Сейчас 17 лет, но проблема здесь.Подход MVVM (на мой взгляд):

public class PreviousDataRefreshBehavior : Behavior<ItemsControl> {
    protected override void OnAttached() {
        var col = (INotifyCollectionChanged)AssociatedObject.Items;
        col.CollectionChanged += OnCollectionChanged;
    }

    protected override void OnDetaching() {
        var col = (INotifyCollectionChanged)AssociatedObject.Items;
        col.CollectionChanged -= OnCollectionChanged;
    }

    private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) {
        if(e.Action != NotifyCollectionChangedAction.Remove) {
            return;
        }

        CollectionViewSource.GetDefaultView(AssociatedObject.ItemsSource).Refresh();
    }
}

и использование:

<ItemsControl>
  <int:Interaction.Behaviors>
    <behaviors:PreviousDataRefreshBehavior/>
  </int:Interaction.Behaviors>
</ItemsControl>
0 голосов
/ 29 июля 2011

Базовая CollectionViewSource должна быть обновлена ​​после удаления.

CollectionViewSource.GetDefaultView(this.Items).Refresh();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...