c# – 对ObservableCollection项的异步更新

我是多线程和 WPF的新手.

我有一个ObservableCollection< RSSFeed&gt ;,应用程序启动项从UI线程添加到此集合中. RSSFeed属性绑定到WPF ListView.后来,我想异步更新每个RSSFeed.所以我正在考虑实现像RSSFeed.FetchAsync()这样的东西,并在其更新的属性上提升PropertyChanged. 我知道ObservableCollection不支持来自UI线程以外的线程的更新,它会抛出NotSupportedException.但是因为我没有操纵ObservableCollection本身而是更新其项目的属性,我可以期待这个工作并看到ListView项目更新吗?或者由于PropertyChanged它会抛出异常吗? 编辑:代码 RSSFeed.cs

public class RSSFeed
{
    public String Title { get; set; }
    public String Summary { get; set; }
    public String Uri { get; set; }        
    public String Encoding { get; set; }
    public List<FeedItem> Posts { get; set; }
    public bool FetchedSuccessfully { get; protected set; }        

    public RSSFeed()
    {
        Posts = new List<FeedItem>();
    }

    public RSSFeed(String uri)
    {
        Posts = new List<FeedItem>();
        Uri = uri;
        Fetch();
    }

    public void FetchAsync()
    { 
        // call Fetch asynchronously
    }

    public void Fetch()
    {
        if (Uri != "")
        {
            try
            {
                MyWebClient client = new MyWebClient();
                String str = client.DownloadString(Uri);

                str = Regex.Replace(str,"<!--.*?-->",String.Empty,RegexOptions.Singleline);
                FeedXmlReader reader = new FeedXmlReader();
                RSSFeed Feed = reader.Load(str,new Uri(Uri));

                if (Feed.Title != null)
                    Title = Feed.Title;
                if (Feed.Encoding != null)
                    Encoding = Feed.Encoding;
                if (Feed.Summary != null)
                    Summary = Feed.Summary;
                if (Feed.Posts != null)
                    Posts = Feed.Posts;

                FetchedSuccessfully = true;
            }
            catch
            {
                FetchedSuccessfully = false;
            }

        }
    }

UserProfile.cs

public class UserProfile : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    public event CollectionChangeEventHandler CollectionChanged;

    private ObservableCollection<RSSFeed> Feeds;
    public ObservableCollection<RSSFeed> Feeds 
    { 
        get { return Feeds; }
        set { Feeds = value; OnPropertyChanged("Feeds"); }
    }

    public UserProfile()
    {
        Feeds = new ObservableCollection<RSSFeed>();
    }

    protected void OnPropertyChanged(string name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this,new PropertyChangedEventArgs(name));
        }
    }

    protected void OnCollectionChanged(RSSFeed Feed)
    {
        CollectionChangeEventHandler handler = CollectionChanged;
        if (handler != null)
        {
            handler(this,new CollectionChangeEventArgs(CollectionChangeAction.Add,Feed));
        }
    }
}

MainWindow.xaml.cs

public partial class MainWindow : Window,INotifyPropertyChanged
{
    // My ListView is bound to this
    // ItemsSource="{Binding Posts}
    public List<FeedItem> Posts
    {
        get 
        {
            if (listBoxChannels.SelectedItem != null)
                return ((RSSFeed)listBoxChannels.SelectedItem).Posts;
            else
                return null;
        }
    }

    private void Window_Loaded(object sender,RoutedEventArgs e)
    {
        // here I load cached Feeds
        // called from UI thread

        // now I want to update the Feeds
        // since network operations are involved,// I need to do this asynchronously to prevent blocking the UI thread
    }

}

谢谢.

解决方法

对于这种应用程序,我通常使用BackgroundWorker并将ReportsProgress设置为True.然后,您可以将每个调用的一个对象作为ReportProgress方法中的userState参数传递. ProgressChanged事件将在UI线程上运行,因此您可以将对象添加到事件处理程序中的ObservableCollection.

否则,从后台线程更新属性将起作用,但如果您正在过滤或排序ObservableCollection,则除非引发了某些集合更改通知事件,否则不会重新应用过滤器.

您可以通过查找集合中项目的索引(例如,通过将其报告为progresspercentage)并设置list.item(i)= e.userstate来重新应用过滤器和排序,即单独替换列表中的项目在ProgressChanged事件中.这样,将保留绑定到集合的任何控件的SelectedItem,而过滤器和排序将遵循项中任何更改的值.

相关文章

在项目中使用SharpZipLib压缩文件夹的时候,遇到如果目录较深,则压缩包中的文件夹同样比较深的问题。比...
项目需要,几十万张照片需要计算出每个照片的特征值(调用C++编写的DLL)。 业务流程:选择照片...
var array = new byte[4]; var i = Encoding.UTF8.GetBytes(100.ToString(&quot;x2&quot;));//...
其实很简单,因为Combox的Item是一个K/V的object,那么就可以把它的items转换成IEnumerable&lt;Dic...
把.net4.6安装包打包进安装程序。 关键脚本如下: 头部引用字符串对比库 !include &quot;WordFunc....
项目需求(Winform)可以批量打印某个模板,经过百度和摸索,使用iTextSharp+ZXing.NetʿreeSp...