在观察到的情况下,由于每次更改都不会更新我的UI



我知道已经有几种类型的问题了。但是我的例子似乎有些不同。此外,WPF和ObservableCollections对我来说仍然是非常新的。因此,将不胜感激。我的电网正在更新,但只有在所有" listoffiles"迭代后才进行更新。我希望它在每个文件找到后更新网格。

注意:我只使用thread.sleep来使过程更可见

xaml

<Window x:Class="WpfApplication2.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:WpfApplication2"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <Button x:Name="btnAdd" Content="Add" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="75" Click="btnAdd_Click"/>
    <DataGrid x:Name="dgFiles" HorizontalAlignment="Left" Margin="90,10,0,0" VerticalAlignment="Top" Height="300" Width="417"/>
</Grid>

c#

using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.IO;
using System.Threading;
using System.Windows;
namespace WpfApplication2
{
    public partial class MainWindow : Window
    {
        public class FilesFound
        {
            public string FileName { get; set; }
            public string FileCount { get; set; }
        }
        private ObservableCollection<FilesFound> file = new ObservableCollection<FilesFound>();
        public MainWindow()
        {
            InitializeComponent();
            dgFiles.ItemsSource = file;
            file.CollectionChanged += this.OnCollectionChanged;
        }
        void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            ObservableCollection<FilesFound> obsSender = sender as ObservableCollection<FilesFound>;
            NotifyCollectionChangedAction action = e.Action;
        }
        private void btnAdd_Click(object sender, RoutedEventArgs e)
        {
            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();
                    this.file.Add(f);
                    Thread.Sleep(500);
                }
            }
        }
    }
}

您应该在背景线程上执行循环,但在UI线程上更新数据observablecollection,因为单个线程不能同时执行两件事。

启动背景线程的最简单方法是使用任务。然后,您可以使用调度程序将访问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);
            }
        }
    });
}

正如您在对帖子的评论中所说的,使用异步/等待等待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和业务逻辑。

最新更新