简体   繁体   English

列表框不更新ItemsSource的内容

[英]Listbox does not update contents of ItemsSource

I have a strange problem with a ListBox: I have bound it to a Collection that does not implement INotifyCollectionChanged (Not possible as it's items are dynamically generated on request): 我在使用ListBox时遇到一个奇怪的问题:我已将其绑定到未实现INotifyCollectionChanged的Collection(不可能,因为它的项目是根据请求动态生成的):

IEnumerator IEnumerable.GetEnumerator()
{
    foreach (var metaData in Metadata.Where((m) => m.IsEnabled))
    {
        yield return new DynamicPropertyValue(this, metaData);
    }
}

Therefore, when IsVisible of the ListBox changes, I'm trying to force to update the ItemsSource by setting it to Null and then update the binding: 因此,当ListBox的IsVisible更改时,我试图通过将ItemsSource设置为Null来强制更新ItemsSource,然后更新绑定:

static void ItemsControl_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
    if (true.Equals(e.NewValue))
    {
        var element = (ItemsControl)sender;
        var bindingExpression = BindingOperations.GetBindingExpression(element, ItemsControl.ItemsSourceProperty);
        if (bindingExpression != null)
        {
            element.SetCurrentValue(ItemsControl.ItemsSourceProperty, null);
            bindingExpression.UpdateTarget();

            var count = element.ItemsSource.OfType<object>().Count();
            if (count != element.Items.Count)
            {
                Debug.WriteLine("Wrong number of items");
            }
        }
    }
}

When the ItemsSource is set to Null, the ItemsControl does not contain any items any more and the Items collection is empt, as expected. 当ItemsSource设置为Null时,ItemsControl将不再包含任何项目,并且Item集合将为空。 However, when applying the binding again, all old items are restored. 但是,再次应用绑定时,将还原所有旧项目。 The Items collection contains the same instances as before. Items集合包含与以前相同的实例。 The GetEnumerator method is called, but the new items are ignored. 调用GetEnumerator方法,但新项目将被忽略。

I don't understand why this is the case or how I can avoid that the ItemsControl caches its Items. 我不明白为什么会这样,或者我如何避免ItemsControl缓存其Items。

Alex 亚历克斯

I stumbled across your post trying to figure out how to accomplish much the same thing. 我偶然发现了您的帖子,试图弄清楚如何完成同样的事情。 Not wanting to use reflection, I kept on researching and found a better answer. 不想使用反射,我继续研究并找到了一个更好的答案。 :) :)

One of the things I am still trying to get used to is how so many features in WPF are accessed not via direct calls to members of the object you're interested in, but in calls to static members which do some behind-the-scenes magic to accomplish the goal. 我仍然想习惯的一件事是,不是通过直接调用您感兴趣的对象的成员,而是通过调用静态成员来访问WPF中的这么多功能,这些静态成员会做一些幕后操作实现目标的魔力。

If I understand your scenario correctly, yours is one of those cases. 如果我正确理解您的情况,那么您就是其中一种情况。 In particular, while you found that getting the CollectionView object via reflection accomplished your goal, the "right" way to do this is to use the CollectionViewSource class to retrieve the CollectionView for the bound object. 尤其是,尽管您发现通过反射获取CollectionView对象可以实现您的目标,但“正确”的方法是使用CollectionViewSource类为绑定的对象检索CollectionView

Without a more complete code example, I can't say what the exact code in your scenario would look like. 没有更完整的代码示例,我无法说出您方案中的确切代码是什么样。 But the basic idea is to do something like this: 但是基本的想法是做这样的事情:

CollectionViewSource.GetDefaultView(itemsSourceObject).Refresh();

Ie this looks up the default view for the object bound to the ItemsSource property (that is, it assumes a variable named itemsSourceObject and passes its value to the method), and then of course calls the Refresh() method to update the view. 即,这将查找绑定到ItemsSource属性的对象的默认视图(也就是说,它假定一个名为itemsSourceObject的变量并将其值传递给该方法),然后当然调用Refresh()方法来更新该视图。

As ListBox.Items.Refresh() does not have the desired effect, I tried a refresh on the underlying CollectionView. 由于ListBox.Items.Refresh()没有达到预期的效果,因此我尝试对基础CollectionView进行刷新。 And voilà - the ListBox updates. 还有-列表框更新。 The problem with this, however, is that the only way to access this CollectionView is using Reflection, as the property is internal: 但是,与此有关的问题是,访问此CollectionView的唯一方法是使用Reflection,因为该属性是内部的:

var collectionViewProperty = typeof (ItemCollection).GetProperty("CollectionView", BindingFlags.Instance | BindingFlags.NonPublic);
var collectionView = (CollectionView) collectionViewProperty.GetValue(itemsControl.Items);
collectionView.Refresh();

It seems that the CollectionView is cached for each ItemsSource that was used with the ItemsControl. 似乎为与ItemsControl一起使用的每个ItemsSource缓存了CollectionView。 Is there any way to change this behavior? 有什么办法可以改变这种行为?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM