【问题标题】:Implementing a ListView with a CollectionViewSource - Not Refreshing?使用 CollectionViewSource 实现 ListView - 不刷新?
【发布时间】:2011-12-19 23:27:14
【问题描述】:

我正在设置一个 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}}" ...

【问题讨论】:

  • CollectionViewSource 是如何设置为 ListView 的?
  • @craig 关于“这是多余的吗?一个比另一个更好吗?”评论:_traits 是一个私有成员,不需要传递给OnPropertyChanged - 毕竟,它不能绑定任何东西来接收更新通知。 OnPropertyChanged("Traits"); 就足够了。
  • @djacobson 谢谢,这有助于澄清事情。
  • this.OnPropertyChanged("Traits");在您的注释行中使用它来判断哪个更好,并且仅当您执行绑定时它看起来像 {Binding Traits} 并且绑定对象的 DataContext 设置为具有 Traits 属性的对象。

标签: c# listview microsoft-metro collectionviewsource


【解决方案1】:

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

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

【讨论】:

  • 感谢您的帮助,但我仍然无法成功连接这些点。据我所知,我没有使用 MVVM,我对 C# 和 WPF 很陌生。从我发布的代码和我见过的其他 MVVM 示例来看,我相当有信心我正在做其他事情。 :)
  • 完全按照我发布的方式设置绑定,并在代码隐藏的加载部分设置this.DataContext = this。看看这是否有效。
【解决方案2】:

与其直接绑定到 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 背景?:))
  • 使用 this 关键字作为前缀的类成员通常是多余的,除非范围内有另一个同名标识符
  • 如果您要在 WPF 中做任何重要的事情,那么值得探索 MVVM 和相关模式;它们帮助您保持视图(XAML 对象)尽可能轻巧且易于更改。

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

【讨论】:

  • 奇怪的是,我的CollectionViewSourceView 属性没有Refresh() 方法
  • 很奇怪,因为 CollectionViewSource.View 属性的类型是 ICollectionView,而 does indeed have a Refresh() method... 如果您调试并中断该 Click 事件,如何this.CollectionViewSource 的 View 属性定义了吗?
  • 我的 CollectionViewSource 也有类似的问题,它拒绝按预期进行更新,这个答案会导致 null 引用异常,因为 CollectionViewSource 的 View 属性始终为 null。
【解决方案3】:

您仍然可以只使用 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>

【讨论】:

    【解决方案4】:

    查看我发布的关于连接 ListView 绑定并适用于所有 CRUD 操作的演示。

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

    【讨论】:

    • 这非常完美。谢谢你把它放在一起,我浏览了一下,这正是我想要的。
    • 上面的链接失效了
    • 需要答案,而不是指向链接已失效的答案的链接。
    • 抱歉,我删除了我的博客。我试图删除此解决方案,但由于它已被选中,我无法删除。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多