You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在类分离场景下实现DataTable动态存储与DataGrid自动更新

问题描述

我需要将数据库中的数据导入DataGrid进行展示,同时实现新数据进入时自动保存到数据库。目前数据收集方法与DataGrid分别位于不同的类中,我知晓可通过合并类的方式,在新对象存入数据库时同步添加至DataGrid,但不希望采用该方案。我曾考虑在数据收集类中创建静态DataTable对象,但认为该方案不够优雅,希望找到更合适的实现方式。

数据收集方法

for (int i = 0; i < inbox.Count; i++)
{
    var message = inbox.GetMessage(i, cancel.Token);
    GetBodyText = message.TextBody;
    Problem problem = new Problem(message.MessageId);
    if (!dAOProblem.GetAll().Any(x => x.Message_Id.Equals(problem.Message_Id)))
    {
        dAOProblem.Save(problem);
        Alert alert = new Alert(message.MessageId, message.Date.DateTime, message.From.ToString(), 1, problem.Id);
        if (!dAOAlert.GetAll().Any(x => x.Id_MimeMessage.Equals(alert.Id_MimeMessage)))
        {
            dAOAlert.Save(alert);
            count = dAOAlert.GetAll().Count();
        }
    }
}

数据展示方法

public void LoadAlertGrid()
{
    SqlConnection con = DatabaseSingleton.GetInstance();
    using (SqlCommand comm = new SqlCommand("SELECT Alert.email , Alert.date , AMUser.name as 'admin', Problem.nameOfAlert, Result.result " +
        "FROM ((Alert INNER JOIN AMUser ON Alert.AMUser_ID = AMUser.id)" +
        " INNER JOIN Problem ON Alert.Problem_ID = Problem.id " +
        "INNER JOIN Result ON Problem.Result_ID = Result.id); ", con))
    {
        DataTable table = new DataTable();
        SqlDataReader sdr = comm.ExecuteReader();
        table.Load(sdr);
        AlertTable.ItemsSource = table.DefaultView;
        sdr.Close();
    }
}
解决方案

1. 基于事件的解耦方案

这是适配类分离场景的优雅方案,通过事件让数据收集类在保存新数据时通知UI类更新DataGrid,完全解耦两个类:

步骤1:在数据收集类中定义事件

public class DataCollector
{
    // 定义事件,传递新增的Alert对象
    public event Action<Alert> AlertAdded;

    public void CollectData(...)
    {
        for (int i = 0; i < inbox.Count; i++)
        {
            var message = inbox.GetMessage(i, cancel.Token);
            GetBodyText = message.TextBody;
            Problem problem = new Problem(message.MessageId);
            if (!dAOProblem.GetAll().Any(x => x.Message_Id.Equals(problem.Message_Id)))
            {
                dAOProblem.Save(problem);
                Alert alert = new Alert(message.MessageId, message.Date.DateTime, message.From.ToString(), 1, problem.Id);
                if (!dAOAlert.GetAll().Any(x => x.Id_MimeMessage.Equals(alert.Id_MimeMessage)))
                {
                    dAOAlert.Save(alert);
                    count = dAOAlert.GetAll().Count();
                    // 触发事件,通知外部新增了Alert
                    AlertAdded?.Invoke(alert);
                }
            }
        }
    }
}

步骤2:在UI类中订阅事件并更新DataGrid

public class AlertGridManager
{
    private DataCollector _dataCollector;
    private DataTable _alertTable;

    public AlertGridManager()
    {
        _dataCollector = new DataCollector();
        // 订阅事件
        _dataCollector.AlertAdded += OnAlertAdded;
        // 初始化加载数据
        LoadAlertGrid();
    }

    public void LoadAlertGrid()
    {
        SqlConnection con = DatabaseSingleton.GetInstance();
        using (SqlCommand comm = new SqlCommand("SELECT Alert.email , Alert.date , AMUser.name as 'admin', Problem.nameOfAlert, Result.result " +
            "FROM ((Alert INNER JOIN AMUser ON Alert.AMUser_ID = AMUser.id)" +
            " INNER JOIN Problem ON Alert.Problem_ID = Problem.id " +
            "INNER JOIN Result ON Problem.Result_ID = Result.id); ", con))
        {
            _alertTable = new DataTable();
            SqlDataReader sdr = comm.ExecuteReader();
            _alertTable.Load(sdr);
            AlertTable.ItemsSource = _alertTable.DefaultView;
            sdr.Close();
        }
    }

    // 事件处理方法:新增Alert时更新DataTable
    private void OnAlertAdded(Alert newAlert)
    {
        // WPF/Silverlight中需通过Dispatcher切换到UI线程
        Application.Current.Dispatcher.Invoke(() =>
        {
            // 查询新增Alert的完整关联数据
            SqlConnection con = DatabaseSingleton.GetInstance();
            using (SqlCommand comm = new SqlCommand("SELECT Alert.email , Alert.date , AMUser.name as 'admin', Problem.nameOfAlert, Result.result " +
                "FROM ((Alert INNER JOIN AMUser ON Alert.AMUser_ID = AMUser.id)" +
                " INNER JOIN Problem ON Alert.Problem_ID = Problem.id " +
                "INNER JOIN Result ON Problem.Result_ID = Result.id) " +
                "WHERE Alert.Id_MimeMessage = @messageId;", con))
            {
                comm.Parameters.AddWithValue("@messageId", newAlert.Id_MimeMessage);
                SqlDataReader sdr = comm.ExecuteReader();
                if (sdr.Read())
                {
                    DataRow newRow = _alertTable.NewRow();
                    newRow["email"] = sdr["email"];
                    newRow["date"] = sdr["date"];
                    newRow["admin"] = sdr["admin"];
                    newRow["nameOfAlert"] = sdr["nameOfAlert"];
                    newRow["result"] = sdr["result"];
                    _alertTable.Rows.Add(newRow);
                }
                sdr.Close();
            }
        });
    }
}

2. 基于ObservableCollection的MVVM方案(更优雅的绑定方式)

若可重构数据展示逻辑,用ObservableCollection<T>替代DataTable,配合MVVM模式可实现自动通知更新:

步骤1:创建数据模型类

public class AlertViewModel
{
    public string Email { get; set; }
    public DateTime Date { get; set; }
    public string Admin { get; set; }
    public string NameOfAlert { get; set; }
    public string Result { get; set; }
}

步骤2:在ViewModel中使用ObservableCollection

public class MainViewModel
{
    public ObservableCollection<AlertViewModel> Alerts { get; } = new ObservableCollection<AlertViewModel>();
    private DataCollector _dataCollector;

    public MainViewModel()
    {
        _dataCollector = new DataCollector();
        _dataCollector.AlertAdded += OnAlertAdded;
        LoadAlerts();
    }

    private void LoadAlerts()
    {
        SqlConnection con = DatabaseSingleton.GetInstance();
        using (SqlCommand comm = new SqlCommand("SELECT Alert.email , Alert.date , AMUser.name as 'admin', Problem.nameOfAlert, Result.result " +
            "FROM ((Alert INNER JOIN AMUser ON Alert.AMUser_ID = AMUser.id)" +
            " INNER JOIN Problem ON Alert.Problem_ID = Problem.id " +
            "INNER JOIN Result ON Problem.Result_ID = Result.id); ", con))
        {
            SqlDataReader sdr = comm.ExecuteReader();
            while (sdr.Read())
            {
                Alerts.Add(new AlertViewModel
                {
                    Email = sdr["email"].ToString(),
                    Date = (DateTime)sdr["date"],
                    Admin = sdr["admin"].ToString(),
                    NameOfAlert = sdr["nameOfAlert"].ToString(),
                    Result = sdr["result"].ToString()
                });
            }
            sdr.Close();
        }
    }

    private void OnAlertAdded(Alert newAlert)
    {
        Application.Current.Dispatcher.Invoke(() =>
        {
            SqlConnection con = DatabaseSingleton.GetInstance();
            using (SqlCommand comm = new SqlCommand("SELECT Alert.email , Alert.date , AMUser.name as 'admin', Problem.nameOfAlert, Result.result " +
                "FROM ((Alert INNER JOIN AMUser ON Alert.AMUser_ID = AMUser.id)" +
                " INNER JOIN Problem ON Alert.Problem_ID = Problem.id " +
                "INNER JOIN Result ON Problem.Result_ID = Result.id) " +
                "WHERE Alert.Id_MimeMessage = @messageId;", con))
            {
                comm.Parameters.AddWithValue("@messageId", newAlert.Id_MimeMessage);
                SqlDataReader sdr = comm.ExecuteReader();
                if (sdr.Read())
                {
                    Alerts.Add(new AlertViewModel
                    {
                        Email = sdr["email"].ToString(),
                        Date = (DateTime)sdr["date"],
                        Admin = sdr["admin"].ToString(),
                        NameOfAlert = sdr["nameOfAlert"].ToString(),
                        Result = sdr["result"].ToString()
                    });
                }
                sdr.Close();
            }
        });
    }
}

步骤3:DataGrid绑定到ObservableCollection

<DataGrid ItemsSource="{Binding Alerts}" AutoGenerateColumns="False">
    <DataGrid.Columns>
        <DataGridTextColumn Header="邮箱" Binding="{Binding Email}" />
        <DataGridTextColumn Header="日期" Binding="{Binding Date}" />
        <DataGridTextColumn Header="管理员" Binding="{Binding Admin}" />
        <DataGridTextColumn Header="告警名称" Binding="{Binding NameOfAlert}" />
        <DataGridTextColumn Header="结果" Binding="{Binding Result}" />
    </DataGrid.Columns>
</DataGrid>

方案优势

  • 事件方案:完全解耦数据收集类和UI类,符合单一职责原则,无需修改原有类核心逻辑,仅需添加事件通知。
  • ObservableCollection方案:贴合WPF的MVVM设计模式,自动触发DataGrid更新,代码简洁易维护。

内容的提问来源于stack exchange,提问作者jirina

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 03:15:48