C# Winform 编程中实现 SQLite3 数据库批量更新与进度条联动?

C# Winform编程 连接sqlite3 进行批量更新 想把方法抽出进行解耦

            public void update(string DBsource, List<string>sqls)
{
            string source = "Data Source= " + DBsource;
            using SqliteConnection sqliteConn = new(source);
            try
            {
                sqliteConn.Open();
                progressBar1.Value = 0;
                progressBar1.Maximum = sqls.Count;
                progressBar1.Visible = true;
                foreach (var item in sqls)
                {
                    SqliteCommand cmd = new(item, sqliteConn);
                    cmd.Prepare();
                    cmd.ExecuteNonQuery();
                    progressBar1.Value++;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            finally { sqliteConn.Close(); }
}

但有对进度条的控制内容
如何让进度中每一个更新,能够转递给外部的控件 progressBar1

阅读 653
avatarAI BotBETA

在C# WinForms中,为了实现SQLite3数据库的批量更新并与进度条联动,你需要将进度更新的逻辑抽取到一个单独的方法中,并通过事件或委托来通知外部控件更新进度条的值。这样,你就可以在调用更新方法时,同时更新UI控件。

下面是一个示例,展示了如何实现这一点:

首先,定义一个委托,用于通知更新进度条的值:

public delegate void ProgressUpdateDelegate(int value);

然后,在更新方法中添加一个事件,当每次执行SQL语句后触发这个事件:

public class DatabaseUpdater
{
    public event ProgressUpdateDelegate ProgressUpdated;

    public void Update(string DBsource, List<string> sqls)
    {
        string source = "Data Source=" + DBsource;
        using SqliteConnection sqliteConn = new(source);
        try
        {
            sqliteConn.Open();
            int totalCount = sqls.Count;
            ProgressBarUpdateHelper.Maximum = totalCount;
            ProgressBarUpdateHelper.Value = 0;
            ProgressBarUpdateHelper.Visible = true;
            
            foreach (var item in sqls)
            {
                SqliteCommand cmd = new(item, sqliteConn);
                cmd.Prepare();
                cmd.ExecuteNonQuery();

                // 触发事件更新进度条
                OnProgressUpdated(1); // 假设每次增加1
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
        finally
        {
            sqliteConn.Close();
        }
    }

    protected virtual void OnProgressUpdated(int value)
    {
        ProgressUpdated?.Invoke(value);
    }
}

在WinForms应用程序中,你需要一个方法来接收这个事件并更新进度条。这通常在你的主窗体类中完成:

public partial class MainForm : Form
{
    private DatabaseUpdater databaseUpdater;

    public MainForm()
    {
        InitializeComponent();
        databaseUpdater = new DatabaseUpdater();
        databaseUpdater.ProgressUpdated += DatabaseUpdater_ProgressUpdated;
    }

    private void DatabaseUpdater_ProgressUpdated(int value)
    {
        // 更新UI,因此需要在控件线程中执行
        if (progressBar1.InvokeRequired)
        {
            progressBar1.Invoke(new ProgressUpdateDelegate(progressBar1.Value = value));
        }
        else
        {
            progressBar1.Value = value;
        }
    }

    private void StartUpdatesButton_Click(object sender, EventArgs e)
    {
        // 假设你有一个列表sqls包含所有的SQL语句
        List<string> sqls = ...;
        databaseUpdater.Update("path_to_your_db", sqls);
    }
}

在上面的代码中,MainForm 类订阅了 DatabaseUpdater 类的 ProgressUpdated 事件,并在事件处理器 DatabaseUpdater_ProgressUpdated 中更新了进度条的值。使用 InvokeRequiredInvoke 方法确保了UI更新在正确的线程上执行。

当你调用 StartUpdatesButton_Click 方法(可能是一个按钮的点击事件)时,它会启动批量更新过程,并且每次更新都会触发 ProgressUpdated 事件,从而更新UI中的进度条。

1 个回答

看你写过 JS。JS 里通常有一个很重要的概念,叫回调函数,可以把一个函数当作参数传递给另一个函数:

function batch(source, callback) {
   let progress = 0;
   source.forEach(item => {
       progress++;
       callback && callback(progress);
   });
}

batch(['甲', '乙', '丙', '丁'], (progress) => {
    console.log(progress);
});

这段代码能理解吧?

在 C# 中也可以实现类似的逻辑,只不过它不叫回调函数,而是叫委托。C# 有两大类委托,一类是没有返回值的(也可以说返回值是 void),是 System.Action<>;另一类是有返回值的,是 System.Func<>

用委托来改写你这段代码的话,就是:

public void update(string DBsource, List<string> sqls, Action<int> onUpdateCallback)
{
    string source = "Data Source= " + DBsource;
    using SqliteConnection sqliteConn = new(source);
    sqliteConn.Open();
    
    int progress = 0;
    if (onUpdateCallback != null)
        onUpdateCallback(progress);
        
    foreach (var item in sqls)
    {
        SqliteCommand cmd = new(item, sqliteConn);
        cmd.Prepare();
        cmd.ExecuteNonQuery();
        
        progress++;
        if (onUpdateCallback != null)
            onUpdateCallback(progress);
    }
}

// 外部调用时
update(DbSource, sqls, (progress) => {
    progressBar1.Value = progress;
    progressBar1.Maximum = sqls.Count;
    progressBar1.Visible = progressBar1.Value < progressBar1.Maximum;
});

当然了,这种写法其实很不 OOP。正常的写法应该是定义一个事件,由外部来监听这个事件再做处理。你既然在做 WinForm,那对事件应该不陌生,WinForm 里所有控件的各种触发都是事件。这个代码就不给了,AI 已经给出一段代码了。

logo
Microsoft
子站问答
访问
宣传栏