删除集合元素时{RelativeSource PreviousData}的问题

时间:2011-07-28 19:51:46

标签: wpf mvvm binding

我正在使用以下(简化)代码在ItemsControl中显示除第一个之外的所有项目中的元素:

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

NullToVisibility是一个简单的转换器,如果源为空,则返回Visibility.Hidden,否则返回Visibility.Visible

现在,这在最初绑定视图或向列表添加元素(ObservableCollection)时工作正常,但删除第一个元素时,第二个元素上的元素不可见

有关如何解决此问题的任何想法?

3 个答案:

答案 0 :(得分:7)

从先前的答案中遗留了一些浪费的代码......不妨在这里使用它:

关键是刷新视图源,例如:

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 :(得分:1)

现在已经开始了,但问题出在这里。 MVVM方法(我认为):

include(dirname(__FILE__).'/../../config/config.inc.php');
require_once('mymodule.php');

$products = MyModule::getAllProducts();

和用法:

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();
    }
}

答案 2 :(得分:0)

删除后必须刷新底层CollectionViewSource

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