【问题标题】:Filling datagrid with async await method使用异步等待方法填充数据网格
【发布时间】:2018-11-05 08:54:56
【问题描述】:

我的英语不是很好很抱歉,但我尽量完美地告诉我的问题

这是我用来加载数据网格的内容

private Task Loading(Func<string> SearchStringForUser)
{

    return Task.Run(() =>
    {

        var query = database.Database.SqlQuery<VW_Users>("select * From VW_Users where 1 = 1 And GymID = " + PublicVar.ID + " " + SearchStringForUser());
        var user = query.ToList();
        Dispatcher.InvokeAsync(() =>
        {
            DataGrid_User.ItemsSource = user;
        });
    });
}

首先我有一个 InvokeAsync 但它不能完美运行我的意思是当加载的数据要列出时我的程序挂起。 无论如何,这不是我的主要问题,但如果有人知道那是什么原因可以指出它 但我的主要问题是当我有 +200 行时。程序不会在 30 秒或更长时间内加载所有日期。看起来我的程序数据网格为 30 秒或更长时间为空。

我想按 10 行 10 行加载数据,我的意思是我想在加载 10 行时填充我的数据网格,在接下来的 10 行之后, 像 10 20 30 40 …… 有了这个我的数据网格永远不会清空 并且数据将缓慢加载 有人能告诉我最好的方法吗?

【问题讨论】:

  • 您不需要使用调度程序。只需将 ItemsSource 分配移出任务。等待查询任务后执行。将 Loading 方法声明为 async。
  • 无论如何它都不会工作,因为我得到错误:调用线程无法访问此对象,因为不同的线程拥有它异步但如果我将 ItemsSource 移出任务,它将异步工作?有可能吗?
  • 还有一个问题,如果它不像 Async 那样工作,为什么它叫 InvokeAsync?还有不同的 beetwen Anvoke 和 InvokeAsync?

标签: c# wpf datagrid


【解决方案1】:

您应该在后台线程上调用数据库,但在 UI 线程上设置 ItemsSource 属性。所以你的Task 应该返回一个IEnumerable&lt;User&gt;,但不要碰DataGrid。然后您可以等待Task

如果从 UI 线程调用 Loading 方法,这应该可以工作:

private async Task Loading(Func<string> SearchStringForUser)
{
    var user = await Task.Run(() =>
    {
        var query = database.Database.SqlQuery<VW_Users>("select * From VW_Users where 1 = 1 And GymID = " + PublicVar.ID + " " + SearchStringForUser());
        return query.ToList();
    });
    DataGrid_User.ItemsSource = user;
}

但由于查询一次返回所有行,因此没有“加载 10 行时”。你一下子就搞定了。如果您不希望这样,您需要使用某种数据阅读器来逐个读取记录。您可以创建一个ObservableCollection 并每隔一段时间填充它。这是一个应该给你想法的例子:

ObservableCollection<VW_Users> collection = new ObservableCollection<VW_Users>();
object @lock = new object();
BindingOperations.EnableCollectionSynchronization(collection, @lock);
DataGrid_User.ItemsSource = collection;

Task.Run(() =>
{
    using (SqlConnection connection = new SqlConnection("connection string...."))
    {
        SqlCommand command = new SqlCommand("select * From VW_Users where GymID = @GymId", connection);
        command.Parameters.AddWithValue("GymId", PublicVar.ID + " " + SearchStringForUser());
        connection.Open();

        SqlDataReader reader = command.ExecuteReader();
        if (reader.HasRows)
        {
            const int N = 10;
            VW_Users[] cache = new VW_Users[N];
            int counter = 0;
            while (reader.Read())
            {
                VW_Users obj = new VW_Users();
                obj.Property1 = Convert.ToString(reader["Column1"]);
                cache[counter] = obj;
                //...and so on for each property...

                if (++counter == N)
                {
                    //add N items to the source collection
                    foreach (VW_Users x in cache) collection.Add(x);
                    counter = 0;
                    //add a delay so you actually have a chance to see that N items are added at a time
                    System.Threading.Thread.Sleep(1000);
                }
            }
            //add any remaining items
            for (int i = 0; i<counter; ++i) collection.Add(cache[i]);
        }
        reader.Close();
    }
});

【讨论】:

  • 非常感谢,它解决了我的问题,你能检查一下我的主要问题吗?
  • @RezaPak:您的查询一次返回所有行,不是吗?所以没有“加载10行时”。你一下子就搞定了。如果您不想要这个,您需要放弃 Entity Framework 或您正在使用的任何 ORM,并使用某种数据阅读器。
  • 你的意思是如何使用数据阅读器?有一个MSDN的例子:docs.microsoft.com/en-us/dotnet/framework/data/adonet/…
  • 感谢您的帮助,我明白了,但是对于最后一个问题,我应该在 while (reader.Read()) { this line } 中写入什么来加载数据并且我的数据网格在启动时不为空
  • @RezaPak:您需要创建 VW_Users 对象,然后将其添加到列表中,然后将 ItemsSource 属性分配给该列表。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-18
  • 1970-01-01
  • 2019-06-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多