使用CollectionViewSource实现ListView - 不刷新?

时间:2011-12-19 23:27:14

标签: c# listview microsoft-metro collectionviewsource

我正在设置一个ListView,其Source属性设置为我的一类ivar,名为Cat

每个Cat都有ObservableCollectionTrait个对象:

private ObservableCollection<Trait> _traits = new ObservableCollection<Trait>();

public ObservableCollection<Trait> Traits
{
get
    {
        return _traits;
    }
}

public void AddTrait(Trait t)
{
    _traits.Add(t);
    // Is this redundant? Is one better than the other?
    this.OnPropertyChanged("_traits");
    this.OnPropertyChanged("Traits");
}

public IEnumerator<Object> GetEnumerator()
{
    return _traits.GetEnumerator();
}

然后我将Source属性分配给此Traits集合:

this.CollectionViewSource.Source = CurrentCat.Traits;

此操作正常,Trait对象在我的ListView中正确显示。

问题是对此基础_traits集合的更改不会导致UI正确更新。例如,这个:

void AddTraitButton_Click(object sender, RoutedEventArgs e)
{
    if (this.CurrentCat != null)
    {
        this.CurrentCat.AddTrait(new Trait());
    }
}

在UI中似乎没有任何影响 ,但如果我像这样重置Source属性:

var oldSource = this.CollectionViewSource.Source;
this.CollectionViewSource.Source = null;
this.CollectionViewSource.Source = oldSource;

然后ListView正确更新。但是,我确信必须有一些我缺少的东西,因为我希望UI能够在添加/删除项目时更新。

修改CollectionViewSource正在应用于我的XAML文件中的ListView

<CollectionViewSource x:Name="CollectionViewSource" x:Key="CollectionViewSource" />

...

<ListView x:Name="ItemListView" ItemsSource="{Binding Source={StaticResource CollectionViewSource}}" ...

4 个答案:

答案 0 :(得分:0)

我现在似乎无法找到它,但我似乎记得绑定到CollectionViewSource的一些问题。您是否尝试直接绑定到CurrentCat.Traits并在代码隐藏中设置this.DataContext = this(我假设您不在此处使用MVVM)?

<ListView x:Name="ItemListView" ItemsSource="{Binding CurrentCat.Traits}" />

答案 1 :(得分:0)

我没有直接绑定到CollectionViewSource并替换它的Source来强制刷新,我相信你想要绑定到CVS的View属性......

<ListView x:Name="ItemListView" 
          ItemsSource="{Binding Source={StaticResource CollectionViewSource}, Path=View}" ...

...并在更新源集合后调用CollectionViewSource.Refresh()

void AddTraitButton_Click(object sender, RoutedEventArgs e)
{
    if (this.CurrentCat != null)
    {
        this.CurrentCat.AddTrait(new Trait());
        this.CollectionViewSource.Refresh();
    }
}

另外,还有一些注意事项,因为您似乎对.NET / WPF约定相对较新:

  • .NET类的私有成员通常称为“字段”而不是“ivars”(Objective-C background?:))
  • 使用this关键字对类成员进行前缀通常是多余的,除非在作用域中有另一个具有相同名称的标识符
  • 如果你在WPF中做任何非平凡的事情,那么值得探索MVVM及相关模式;它们可以帮助您保持视图(XAML对象)尽可能轻松且易于更改。

    在您的情况下,例如,我假设您显示的代码来自任何Window或UserControl包含ListView的代码隐藏。遵循MVVM模式将涉及创建一个单独的“ViewModel”类,该类将包含Traits集合并通过CollectionViewSource公开它(使用View属性,正如我所提到的)。然后,您的UserControl将ViewModel的实例指定为其DataContext,并且ListView可以绑定到公开的CollectionView。

答案 2 :(得分:0)

您可以专门使用ObservableCollection。虽然存在一个问题 - 但它不会在IsInDesignMode中显示数据。也许将来它会有所改善。

public class MainViewModel : ViewModelBase
{
...
    private ObservableCollection<PartViewModel> _parts;
    public ObservableCollection<PartViewModel> Parts
    {
        get
        {
            if (_parts == null)
            {
                _parts = new ObservableCollection<PartViewModel>();
                _parts.CollectionChanged += _parts_CollectionChanged;
            }
            return _parts;
        }
    }

    object m_ReorderItem;
    int m_ReorderIndexFrom;
    void _parts_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        switch (e.Action)
        {
            case NotifyCollectionChangedAction.Remove:
                m_ReorderItem = e.OldItems[0];
                m_ReorderIndexFrom = e.OldStartingIndex;
                break;
            case NotifyCollectionChangedAction.Add:
                if (m_ReorderItem == null)
                    return;
                var _ReorderIndexTo = e.NewStartingIndex;
                m_ReorderItem = null;
                break;
        }
    }

    private PartViewModel _selectedItem;
    public PartViewModel SelectedItem
    {
        get
        {
            return _selectedItem;
        }
        set
        {
            if (_selectedItem != value)
            {
                _selectedItem = value;
                RaisePropertyChanged("SelectedItem");
            }
        }
    }
   ...

    #region ViewModelBase

    public override void Cleanup()
    {
        if (_parts != null)
        {
            _parts.CollectionChanged -= _parts_CollectionChanged;
        }
        base.Cleanup();
    }

    #endregion

  }

<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
    <Grid.Resources>
        <CollectionViewSource x:Name="PartsCollection" Source="{Binding Parts}"/>
    </Grid.Resources>

    <ListView Margin="20" CanReorderItems="True" CanDragItems="True" AllowDrop="True" 
              ItemsSource="{Binding Source={StaticResource PartsCollection}}" SelectedItem="{Binding SelectedItem, Mode=TwoWay}" SelectionMode="Single">
        <ListView.ItemContainerStyle>
            <Style TargetType="ListViewItem">
                <Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
            </Style>
        </ListView.ItemContainerStyle>
        <ListView.ItemTemplate>
        ...
        </ListView.ItemTemplate>
    </ListView>
</Grid>

答案 3 :(得分:-5)

查看我提出的关于获取ListView绑定并为所有CRUD操作工作的演示。

http://www.flaskofespresso.com/2012/01/windows-8-metro-app-listview-binding-and-editing/