ExecuteReader 进程到文本框

executereader process to textbox

提问人:This lowly newb 提问时间:5/18/2017 最后编辑:This lowly newb 更新时间:5/18/2017 访问量:106

问:

假设我有一个从按钮单击方法 (winforms) 触发的数据处理方法

业务对象

public class MembershipCard
    {
        public int ID { get; set; }
        public string MemberCode { get; set; }
        public string MemberName { get; set; }
        public string MemberCard { get; set; }
        public byte[] MemberCardImage { get; set; }
    }

所以我想让应用程序更具响应性,比如在检索数据时,我把一个多行文本框作为进程状态,在执行读取器时,它会像

Textbox1.Text = "Retrieving member data, Member Identity" + obj.MemberName ... ... + Environment.NewLine;

或者像“处理成员”一样进行处理时......

类似的东西,因为数据有点大(>100.000 行),所以单击按钮后,应用程序将没有响应(显然没有响应)

我写的代码有点没有按照我想要的方式工作

using (var reader = mySql.ExecuteReader())
                {
                    if (reader.HasRows)
                    {
                        MembershipCard obj;
                        while (reader.Read())
                        {
                            obj = new MembershipCard();
                            if (!reader.IsDBNull(reader.GetOrdinal("ID")))
                            {
                                obj.ID = Convert.ToInt32(reader["ID"]);
                            }
                            if (!reader.IsDBNull(reader.GetOrdinal("MemberCode")))
                            {
                                obj.MemberCode = Convert.ToString(reader["MemberCode"]);
                            }
                            if (!reader.IsDBNull(reader.GetOrdinal("MemberName")))
                            {
                                obj.MemberName = Convert.ToString(reader["MemberName"]);
                            }
                            if (!reader.IsDBNull(reader.GetOrdinal("MemberCard")))
                            {
                                obj.MemberCard = Convert.ToString(reader["MemberCard"]);
                                if (!string.IsNullOrEmpty(obj.MemberCard))
                                {
                                    QRCode qrCode = new QRCode();
                                    qrCode.Data = obj.MemberCard;
                                    qrCode.ModuleSize = 3;

                                    qrCode.LeftMargin = 0;
                                    qrCode.RightMargin = 0;
                                    qrCode.TopMargin = 0;
                                    qrCode.BottomMargin = 0;

                                    qrCode.UOM = UnitOfMeasure.PIXEL;

                                    qrCode.Encoding = BarcodeLib.Barcode.QRCodeEncoding.Auto;
                                    qrCode.ECL = BarcodeLib.Barcode.QRCodeErrorCorrectionLevel.L;

                                    qrCode.ImageFormat = System.Drawing.Imaging.ImageFormat.Png;

                                    obj.MemberCardImage = qrCode.drawBarcodeAsBytes();
                                }
                            }


                            textBox1.Text = "Getting member data, Member: " + obj.MemberName + "/" + obj.MemberCode + "/" + obj.MemberCard;

                            result.Add(obj);
                        }
                        reader.Close();
                    }

TLDR:在执行 时,在文本框上实时写入进程SqlCommand.ExecuteReader()

提前致谢

C# WinForms

评论


答:

0赞 bluekushal 5/18/2017 #1

您应该在单独的线程上检索数据,以使 UI 具有响应性。尝试使用后台工作线程。

这相当简单。这是 MSDN 链接

1赞 Harald Coppoolse 5/18/2017 #2

如今,在winforms中,有两种方法被广泛用于在执行大型计算时保持程序的响应速度。一个是使用后台工作线程,另一个是使用 async-await。

后台工作线程更适合于不太频繁地启动(不是每秒几次)的计算,这将需要相当长的时间(几秒钟、几分钟),因为启动后台工作线程意味着在后台工作线程需要访问主线程也访问的数据时启动一个单独的线程,其中包含所有问题(死锁、InvokeRequired 等)。

如果您有相当短的计算,可能需要经常启动,则使用 Async-await。如果您不想启动新线程的开销,并且想要看起来相当同步的代码,则可以使用它。

我曾经为我的后台计算、检索数据、写入文件等创建后台工作线程,但现在我越来越多地使用 async-await 来做到这一点。代码看起来更简单,更易于维护。

这次对 Eric Lippert 的采访帮助我了解了异步等待的工作原理。在中间的某个地方搜索异步等待

在这篇文章中,Eric Lippert 将异步等待比作厨师准备饭菜。每当他必须等待某件事完成时,他就会开始环顾四周,看看他是否可以做其他事情,而不是无所事事地等待。

async-await 也是如此。每当程序必须等待加载文件、执行数据库查询、下载互联网数据等内容时,async-await 程序都会环顾四周,看看它是否可以执行其他操作,例如响应用户输入。

在这篇文章中,乐于助人的 Stephen Cleary 解释了 async-await 的基础知识。

主要特点:

  • 如果过程想要调用异步函数,则必须将其本身声明为异步
  • 每个异步过程返回 instead of 和 instead ofTaskvoidTask<TResult>TResult
  • 只有一个例外:异步事件处理程序返回 。void
  • 通常,异步过程中至少有一个等待。事实上,如果你忘记在某个地方等待,你的编译器会警告你。
  • await 的返回值将是 when you waitit 和 when you waitit 。voidTaskTResultTask<TResult>

如果异步过程调用其他异步过程,则此其他过程中的代码将执行,就好像它不是异步过程一样,直到它遇到 await。线程不会什么都不做,而是上升其调用堆栈并执行代码,直到遇到 await。线程再次上升到调用堆栈,等等。一旦每个人都在等待,它就会回到第一个等待,直到这个任务完成。由于 UI 无法等待您的过程完成,因此只要您的线程不执行任何计算(只要您的厨师正在等待面包烘烤),您的线程就可以自由地保持 UI 响应(厨师可以自由地执行其他操作)

请注意,如果您的线程执行计算,则它不会等待某些内容,因此您的 UI 不会响应。因此,您应该启动另一个线程来执行计算,并仅在需要时等待结果。

在你的情况下,以下代码将使你的 UI 保持响应。

public async void OnButton1_clicked(object sender, ...)
{
    await this.UpdateData();
    // I chose to split the event from the action, so others like menu items
    // could also call UpdateData();
    // Besides it is a nice example of a function that returns Task instead of void 
}

请注意,尽管此事件处理程序声明为 async,但它返回 void。

public async Task UpdateData()
{
    // start a Task that will read the database, but don't await
    var myReadTask = Task.Run( () => ReadDatabaseData(...));

    // because you are not awaiting you are free to do other things here
    // like informing the operator that the data is being read:
    // note that this code is performed by the thread that has the UI context
    // so you are free to use the textbox

    Textbox1.Text = "Retrieving member data ...";

    // once you need the data await for it. The return value is the "TResult"
    MyReadData data = await myReadTask;
    // here you are certain that the data has been read
    Textbox1.Text = "Finished reading data";
    ProcessReadData(data);
}

UpdateData返回而不是 。它被声明为异步,因此其中至少有一个 await。Taskvoid

当然,如果您在读取数据时无事可做,则可以执行以下操作:

public async Task UpdateData()
{
    Textbox1.Text = "Retrieving member data ...";
    MyReadData data = await Task.Run( () => ReadDatabaseData(...));
    Textbox1.Text = "Finished reading data";
    ProcessReadData(data);
}

将读取数据的异步过程不应执行任何与 UI 相关的操作:

public async Task<MyReadData> ReadDatabaseData(...)
{
    using (var reader = mySql.ExecuteReader())
    {
        // Read the data, don't do anything UI-related
        return myReadData;
    }
}

我认为async-await的美妙之处在于您的代码看起来像是同步执行的。没有争用条件,不需要使用互斥锁来保护代码中的关键部分。执行线程具有 UI 线程的上下文(例如:它可以执行 UI 线程可以执行的操作),您不需要类似 .InvokeRequired