简体   繁体   English

绑定的ObservableCollection更改时,ListView不更新

[英]ListView not updating when the bound ObservableCollection changes

I'm working on an search window that loads search results into an ObservableCollection and then displays the results using a ListView. 我正在使用一个搜索窗口,它将搜索结果加载到ObservableCollection中,然后使用ListView显示结果。

Setting the ListView's ItemSource to the ObservableCollection after the search is complete populates the list correctly. 搜索完成后,将ListView的ItemSource设置为ObservableCollection可以正确填充列表。

I'm trying to get the ListView to update as the search adds additional results, but the ListView doesn't populate with any data at all. 我正在尝试更新ListView,因为搜索添加了其他结果,但是ListView根本没有填充任何数据。 I can't work out where my binding is falling over. 我无法解决我的绑定丢失的地方。

My research showed various ways of using DataContext, though none seem to help; 我的研究显示了使用DataContext的各种方法,尽管似乎没有帮助。 I've tried assigning it to "this" and to my CachedData class using CodeBehind as well as at the xaml Window level. 我尝试使用CodeBehind以及xaml Window级别将其分配给“ this”和CachedData类。

Sorry for the long code snippets, I've left anything that I think may help add context to the question. 很抱歉,很长的代码片段,我遗漏了我认为可能有助于在问题中添加上下文的任何内容。

XAML: XAML:

<Window x:Class="SLX_Interface.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:SLX_Interface"
    mc:Ignorable="d"
    Title="SLX Search" Height="auto" Width="auto">
<Window.CommandBindings>
</Window.CommandBindings>
<Grid>
    <Grid.Resources>
        <local:CachedData x:Key="cachedData" />
    </Grid.Resources>
    <TabControl x:Name="tabControl" Grid.RowSpan="2" Margin="0,20,0,0">
        <TabItem Header="Accounts" Name="accountsTab">
            <Grid>
                <ListView x:Name="accountSearchResultsListView" Margin="5,32,5,30" DataContext="staticResource cachedData" ItemsSource="{Binding Path=accounts}" IsSynchronizedWithCurrentItem="True">
                    <ListView.View>
                        <GridView x:Name="accountSearchResultsGridView">
                            <GridViewColumn Header="SData Key" DisplayMemberBinding="{Binding SDataKey}"/>
                            <GridViewColumn Header="Account Name" DisplayMemberBinding="{Binding AccountName}"/>
                        </GridView>
                    </ListView.View>
                </ListView>
             </Grid>
        </TabItem>
    </TabControl>
</Grid>

Code-Behind from within MainWindow.xaml.cs: 从MainWindow.xaml.cs内部进行代码隐藏:

private async void SearchAccount(string searchTerm, string searchField, string searchOperator)
    {
        //Create the string we'll use for searching
        string urlString = "Stuff";

        //Create an ObservableCollection, then use it to blank the cache
        ObservableCollection<Account> resultsList = new ObservableCollection<Account>();
        CachedData.accounts = resultsList;

        //Getting data from the search using an XML Reader
        XmlReader resultsReader = null;

        try
        {
            //Using XmlReader to grab the search results from SLX
            XmlUrlResolver resultsResolver = new XmlUrlResolver();
            resultsResolver.Credentials = LoginCredentials.userCred;

            XmlReaderSettings resultsReaderSettings = new XmlReaderSettings();
            resultsReaderSettings.XmlResolver = resultsResolver;
            resultsReaderSettings.Async = true;

            resultsReader = XmlReader.Create(urlString, resultsReaderSettings);
        }
        catch (Exception error)
        {

        }

        //Grabbing data from the XML and storing it, hopefully updating the ListView as we go
        using (resultsReader)
        {
            while (await resultsReader.ReadAsync())
            {
                while (resultsReader.ReadToFollowing("slx:Account"))
                {
                    //Setting data from the XML to a new Account object ready to be passed to the list
                    Account account = new Account();
                    account.GUID = new Guid();

                    resultsReader.MoveToFirstAttribute(); account.SDataKey = resultsReader.Value;
                    resultsReader.ReadToFollowing("slx:AccountName"); account.AccountName = resultsReader.ReadElementContentAsString();

                    CachedData.accounts.Add(account);

                    //--Uncommenting this gives odd results;
                    //--The first item is displayed, any others aren't.
                    //--If there are a lot of items, the application eventually errors like mad and ends.
                    //--Looks like one error window for each item, though I don't see the message before they die along with the application.
                    //accountSearchResultsListView.ItemsSource = CachedData.accounts;
                }
            }
        }

        //--Uncommenting this works but shows the data once the entire XML has been read through, which can take some time so isn't ideal.
        //accountSearchResultsListView.ItemsSource = CachedData.accounts;        }

Classes references above, stored in a separate .cs file but under the same namespace: 上面的类引用,存储在单独的.cs文件中,但在相同的名称空间下:

public class CachedData
{
    public static ObservableCollection<Account> accounts { get; set; }

    public static event PropertyChangedEventHandler PropertyChanged;

    public static event EventHandler<PropertyChangedEventArgs> StaticPropertyChanged = delegate { };
    private static void NotifyStaticPropertyChanged(string propertyName)
    {
        StaticPropertyChanged(null, new PropertyChangedEventArgs(propertyName));
    }
}

public class Account : IEquatable<Account>
{
    public Guid GUID { get; set; }
    public string SDataKey { get; set; }
    public string AccountName { get; set; }

    public override string ToString()
    {
        return AccountName;
    }

    public override bool Equals(object obj)
    {
        if (obj == null) return false;
        Account objAsPart = obj as Account;
        if (objAsPart == null) return false;
        else return Equals(objAsPart);
    }

    public override int GetHashCode()
    {
        return 0;
    }

    public bool Equals(Account other)
    {
        if (other == null) return false;
        return (GUID.Equals(other.GUID));
    }
}

I appreciate any help you can offer, this has stumped me for days now. 我感谢您可以提供的任何帮助,这已经困扰了我好几天了。

When you set a data binding in xaml, an instance of ObservableCollection which exists when the app starts will be bound. 在xaml中设置数据绑定时,将绑定应用程序启动时存在的ObservableCollection实例。 So DO instantiate an instance before the app starts and DO NOT replace it with new instance unless you reset the data binding in code behind. 因此,请务必在应用启动之前实例化一个实例,并且不要用新实例替换它,除非您在后面的代码中重置了数据绑定。 If you need to clear its elements, use Clear method. 如果需要清除其元素,请使用Clear方法。

The problem is you are using ObservableCollection which implements INotifyCollectionChanged internally. 问题是您使用的是内部实现INotifyCollectionChanged的 ObservableCollection which doesn't raise every change to collection. 这并不会引起对收藏的任何改变。 It will raise a collection change only when an item is added or removed from collection. 仅当添加或从集合中删除项目时,它才会引发集合更改

So the problem occurs what will happen if someone assign a new instance of collection ( as your case ). 因此,如果有人分配一个新的collection实例( 视您的情况 ),将会发生问题。 so resetting the binding is not really good option instead you can raise the change yourself. 因此重置绑定不是一个很好的选择,而是可以自己进行更改。 by simply implementing the INotifyPropertyChanged.(usual cases) 通过简单地实现INotifyPropertyChanged。(通常情况下)

public class DataClass : INotifyPropertyChanged
{

    public event PropertyChangedEventHandler PropertyChanged;

    public void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }


    private ObservableCollection<string> collection;

    public ObservableCollection<string> Collection
    {
        get { return collection; }
        set
        {
            collection = value;
            OnPropertyChanged("Collection");
        }
    }       
}

so assigning the collection to null or a new instance will also get reflected to bound control. 因此将集合分配为null或新实例也将反映到绑定控件中。 (you have already have NotifyStaticPropertyChanged you just need to create a full property and just raise the change when required.) (您已经有了NotifyStaticPropertyChanged,您只需要创建一个完整的属性,并在需要时提出更改即可。)

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

相关问题 当ObservableCollection绑定更改时,Listview不会更新 - Listview doesn't update when the ObservableCollection its bound to changes 当更新绑定到Listview的ObservableCollection中的Item时,指定的强制转换无效 - Specified cast not Valid when updating Item in ObservableCollection bound to Listview 从UI更改ObservableCollection而不更新Bound Collection - Changes to ObservableCollection from UI not updating the Bound Collection 更换ObservableCollection时ListView不更新 - ListView not updating when ObservableCollection is replaced 绑定到ObservableCollection的TextBox无法更新 - TextBox bound to ObservableCollection not updating 基础ObservableCollection更改时,ComboBox项未更新 - ComboBox items not updating when underlying ObservableCollection changes 的ObservableCollection <DateTime> 并在项目更改时更新用户界面 - ObservableCollection<DateTime> and updating the UI when the item changes 在ObservableCollection中更改模型属性时更新UI? - Updating UI when a model property changes in an ObservableCollection? 绑定到ObservableCollection的ListView <T> 添加到媒体资源时不更新 - ListView bound to ObservableCollection<T> Doesn't update when Added to property 在从绑定的ObservableCollection中添加或删除项目时更新视图 - Updating the View when items are added or removed from a bound ObservableCollection
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM