如何使用SqlDatareader读取记录时通知UI

时间:2016-06-02 22:09:53

标签: c# wpf sqldatareader

我有以下方法

    array_filter($yourArrayToFilter, function($value) {
      return (is_null($value))? false : true;
    });

它将在WPF应用程序中使用,我希望能够通知UI读取进度。我必须举办一个简单的活动吗?就像是 OnProgress(new MyProgressEventHandler(recordcounter));我确信这样的方法会在执行时冻结UI,是否有更好的事情可以做,例如使用asyncronous方法仍然等待方法执行但是能够通知用户它正在做什么?

2 个答案:

答案 0 :(得分:2)

you can pass in a IProgress<T> and use it's Report(T) method. If the object backing the interface is a Progress<T> it will automaticly marsal the callback on the UI if the object was created on the UI thread.

//elsewhere
public class GetAllProgress
{
    public GetAllProgress(int count, int total)
    {
        Count = count;
        Total = total;
    }

    public Count {get;}
    public Total {get;}
}

public List<VatRate> GetAll( string cnString, IProgress<GetAllProgress> progress )
{
    List<VatRate> result = new List<VatRate>();
    using (SqlConnection cn = new SqlConnection(cnString))
    {
        SqlCommand cmd = new SqlCommand();
        cmd.Connection = cn;
        cmd.CommandText = SQL_SELECT_COUNT;
        //You don't need to do set CommandType to text, it is the default value.
        cn.Open();

        var totalCount = (int)cmd.ExecuteScalar();
        progress.Report(new GetAllProgress(0, totalCount));

        cmd.CommandText = SQL_SELECT; 
        using(SqlDataReader reader = cmd.ExecuteReader())
        {
            //reader.HasRows is unnecessary, if there are no rows reader.Read() will be false the first call
            while (reader.Read())
            {
                VatRate vr = new VatRate();
                vr.IDVatRate = reader["IDVatRate"] == System.DBNull.Value ? Guid.Empty : (Guid)reader["IDVatRate"];
                vr.Percent = reader["Percent"].XxNullDecimal();
                vr.Type = reader["Type"].XxNullString();
                vr.VatRateDescription = reader["VatRateDescription"].XxNullString();
                result.Add(vr);
                progress.Report(new GetAllProgress(result.Count, TotalCount));
            }
            //I put reader in a using so you don't need to close it.
        }
        //You don't need to do cn.Close() inside a using
    }
    return result;
}

You can then call GetAll on a background thread (just be sure to call new Progress<GetAllProgress>() on the UI thread) or re-write the function to be async.

public async Task<List<VatRate>> GetAllAsync( string cnString, IProgress<GetAllProgress> progress )
{
    List<VatRate> result = new List<VatRate>();
    using (SqlConnection cn = new SqlConnection(cnString))
    {
        SqlCommand cmd = new SqlCommand();
        cmd.Connection = cn;
        cmd.CommandText = SQL_SELECT_COUNT;

        //The .ConfigureAwait(false) makes it so it does not need to wait for the UI thread to become available to continue with the code.
        await cn.OpenAsync().ConfigureAwait(false);

        var totalCount = (int)await cmd.ExecuteScalarAsync().ConfigureAwait(false);
        progress.Report(new GetAllProgress(0, totalCount));

        cmd.CommandText = SQL_SELECT; 
        using(SqlDataReader reader = await cmd.ExecuteReaderAsync().ConfigureAwait(false))
        {
            while (await reader.ReadAsync().ConfigureAwait(false))
            {
                VatRate vr = new VatRate();
                vr.IDVatRate = reader["IDVatRate"] == System.DBNull.Value ? Guid.Empty : (Guid)reader["IDVatRate"];
                vr.Percent = reader["Percent"].XxNullDecimal();
                vr.Type = reader["Type"].XxNullString();
                vr.VatRateDescription = reader["VatRateDescription"].XxNullString();
                result.Add(vr);
                progress.Report(new GetAllProgress(result.Count, TotalCount));
            }
        }
    }
    return result;
}

答案 1 :(得分:0)

@Scott张伯伦的答案很棒,我建议使用async / await解决方案。

在这里,我只为WPF添加一些部分。

在WPF中,您可以使用<ProgressBar>,只需设置值即可显示进度。

<Grid>
    <ProgressBar x:Name="progressBar" HorizontalAlignment="Left" Height="22" Margin="59,240,0,0" VerticalAlignment="Top" Width="383"/>
</Grid>

当您致电GetAllAsync时,您实际上可以像下面一样轻松编写代码:

await GetAllAsync(new Progress<GetAllProgress>(progress=> { progressBar.Maximum = progress.Total; progressBar.Value = progress.Count; } ));
顺便说一下,最好使用MVVM模式并将你的ADO逻辑与UI分离,你可以看看这个article