C# ObservableCollection在每次更改时都无法更新我的UI

C# ObservableCollection在每次更改时都无法更新我的UI,c#,wpf,observablecollection,C#,Wpf,Observablecollection,我知道已经有一些这样的问题了。但我的例子似乎有点不同。此外,WPF和ObservableCollections对我来说还是很新的。因此,我们将不胜感激。我的网格正在更新,但只有在它遍历所有“listOfFiles”之后才更新。我希望它在找到每个文件后更新网格 注意:我只使用Thread.Sleep使进程更可见 XAML C# 使用System.Collections.ObjectModel; 使用System.Collections.Specialized; 使用System.IO; 使用

我知道已经有一些这样的问题了。但我的例子似乎有点不同。此外,WPF和ObservableCollections对我来说还是很新的。因此,我们将不胜感激。我的网格正在更新,但只有在它遍历所有“listOfFiles”之后才更新。我希望它在找到每个文件后更新网格

注意:我只使用Thread.Sleep使进程更可见

XAML


C#

使用System.Collections.ObjectModel;
使用System.Collections.Specialized;
使用System.IO;
使用系统线程;
使用System.Windows;
命名空间WpfApplication2
{
公共部分类主窗口:窗口
{
找到公共类文件
{
公共字符串文件名{get;set;}
公共字符串文件计数{get;set;}
}
私有ObservableCollection文件=新ObservableCollection();
公共主窗口()
{
初始化组件();
dgFiles.ItemsSource=文件;
file.CollectionChanged+=this.OnCollectionChanged;
}
CollectionChanged无效(对象发送方,NotifyCollectionChangedEventArgs e)
{
ObservableCollection obsSender=作为ObservableCollection的发送方;
NotifyCollectionChangedAction动作=e.动作;
}
私有无效btnAdd_单击(对象发送者,路由目标e)
{
字符串[]listOfFiles=Directory.GetFiles(@“C:\TEST\”、“***”、SearchOption.AllDirectories);
整数计数=0;
foreach(listOfFiles中的var文件)
{
if(file.Contains(“客户端”))
{
计数++;
FilesFound f=newfilesfound();
f、 文件名=文件;
f、 FileCount=count.ToString();
此.file.Add(f);
睡眠(500);
}
}
}
}
}

正如您在帖子评论中所说,使用async/await应该可以释放UI线程(无论如何,这是我以前使用的方法)

所以你需要一些类似的东西:

    private async void btnAdd_Click(object sender, RoutedEventArgs e)
    {
        string[] listOfFiles = Directory.GetFiles(@"C:\TEST\", "*.*", SearchOption.AllDirectories);
        await Task.Run(() =>
            {
                int count = 0;
                foreach (var file in listOfFiles)
                {
                    if (file.Contains("CLIENT"))
                    {
                        count++;
                        FilesFound f = new FilesFound();
                        f.FileName = file;
                        f.FileCount = count.ToString();
                        this.file.Add(f);
                        Thread.Sleep(500);
                    }
                }
            });
    }

作为补充说明,您可能应该使用MVVM和ICommand界面来分离UI和业务逻辑。

您应该在后台线程上执行循环,但在UI线程上更新databound ObservableCollection,因为单个线程不能同时做两件事

启动后台线程的最简单方法是使用任务。然后,您可以使用dispatcher将访问ObservableCollection的任何调用封送回UI线程。试试这个:

private void btnAdd_Click(object sender, RoutedEventArgs e)
{
    Task.Run(() =>
    {
        string[] listOfFiles = Directory.GetFiles(@"C:\TEST\", "*.*", SearchOption.AllDirectories);
        int count = 0;
        foreach (var file in listOfFiles)
        {
            if (file.Contains("CLIENT"))
            {
                count++;
                FilesFound f = new FilesFound();
                f.FileName = file;
                f.FileCount = count.ToString();
                Dispatcher.BeginInvoke(new Action(() => this.file.Add(f)));
                Thread.Sleep(500);
            }
        }
    });
}

foreach
循环在UI线程中运行并阻止它,直到它完成。调用
Thread.Sleep()
会让事情变得更糟。查看或。您正在UI线程中执行此操作。这意味着在该操作完成之前,UI没有任何机会进行更新。我认为使用ObservableCollection可以缓解这种情况。ObservableCollection应该如何使您的循环异步?ObservableCollection与并行性和异步操作无关,它只是通知集合的更改。如果我在其中添加Asynch/Wait,我希望做的事情可能吗?
    private async void btnAdd_Click(object sender, RoutedEventArgs e)
    {
        string[] listOfFiles = Directory.GetFiles(@"C:\TEST\", "*.*", SearchOption.AllDirectories);
        await Task.Run(() =>
            {
                int count = 0;
                foreach (var file in listOfFiles)
                {
                    if (file.Contains("CLIENT"))
                    {
                        count++;
                        FilesFound f = new FilesFound();
                        f.FileName = file;
                        f.FileCount = count.ToString();
                        this.file.Add(f);
                        Thread.Sleep(500);
                    }
                }
            });
    }
private void btnAdd_Click(object sender, RoutedEventArgs e)
{
    Task.Run(() =>
    {
        string[] listOfFiles = Directory.GetFiles(@"C:\TEST\", "*.*", SearchOption.AllDirectories);
        int count = 0;
        foreach (var file in listOfFiles)
        {
            if (file.Contains("CLIENT"))
            {
                count++;
                FilesFound f = new FilesFound();
                f.FileName = file;
                f.FileCount = count.ToString();
                Dispatcher.BeginInvoke(new Action(() => this.file.Add(f)));
                Thread.Sleep(500);
            }
        }
    });
}