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

WPF应用如何动态获取Web端新增的数据库数据?

问题场景

我有一个Web应用,用户提交的信息会存入数据库。当前WPF应用启动时会读取数据库并填充DataGrid,但Web端新增数据后,WPF无法自动更新DataGrid,必须重启页面才能看到新增内容。由于Web应用由其他客户托管,无法对其进行修改。

我考虑了两种方案:

  1. 数据库添加IsNew标记列+触发器+定时轮询
  2. 通过API接口实现

以下是两种方案的具体实现方式及最优选择分析:


方案一:数据库触发器+定时轮询实现

1. 数据库端配置

  • 添加IsNew布尔列:在目标数据表新增BIT类型的IsNew列,默认值设为0。
  • 创建数据库触发器:
    针对INSERT/UPDATE操作,自动将IsNew设为1(以SQL Server为例):
    CREATE TRIGGER Trigger_SetIsNew
    ON YourTableName
    AFTER INSERT, UPDATE
    AS
    BEGIN
        SET NOCOUNT ON;
        UPDATE t
        SET t.IsNew = 1
        FROM YourTableName t
        INNER JOIN inserted i ON t.Id = i.Id;
    END
    

2. WPF端轮询实现

在ViewModel中使用DispatcherTimer定时轮询数据库,获取新数据后更新DataGrid,并将IsNew重置为0。

ViewModel核心代码

public class MainViewModel : INotifyPropertyChanged
{
    private DispatcherTimer _pollingTimer;
    private ObservableCollection<YourModel> _dataGridItems;
    public ObservableCollection<YourModel> DataGridItems
    {
        get => _dataGridItems;
        set
        {
            _dataGridItems = value;
            OnPropertyChanged();
        }
    }

    public MainViewModel()
    {
        DataGridItems = new ObservableCollection<YourModel>();
        InitializePollingTimer();
        LoadInitialData();
    }

    private void InitializePollingTimer()
    {
        _pollingTimer = new DispatcherTimer();
        _pollingTimer.Interval = TimeSpan.FromSeconds(10); // 可调整轮询间隔
        _pollingTimer.Tick += PollingTimer_Tick;
        _pollingTimer.Start();
    }

    private async void PollingTimer_Tick(object sender, EventArgs e)
    {
        try
        {
            var newItems = await YourDataService.GetNewOrUpdatedItemsAsync();
            if (newItems.Any())
            {
                // 更新DataGrid数据
                foreach (var item in newItems)
                {
                    var existingItem = DataGridItems.FirstOrDefault(x => x.Id == item.Id);
                    if (existingItem != null)
                    {
                        existingItem.Property1 = item.Property1;
                        existingItem.Property2 = item.Property2;
                    }
                    else
                    {
                        DataGridItems.Add(item);
                    }
                }
                // 标记数据已处理
                await YourDataService.MarkItemsAsProcessedAsync(newItems.Select(x => x.Id));
            }
        }
        catch (Exception ex)
        {
            // 异常处理(如日志记录)
            Console.WriteLine($"轮询出错:{ex.Message}");
        }
    }

    private void LoadInitialData()
    {
        var initialData = YourDataService.GetAllItems();
        foreach (var item in initialData) DataGridItems.Add(item);
    }

    // INotifyPropertyChanged实现
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

DataService核心方法

public class YourDataService
{
    private string _connStr = "YourDatabaseConnectionString";

    public async Task<List<YourModel>> GetNewOrUpdatedItemsAsync()
    {
        var items = new List<YourModel>();
        using (var conn = new SqlConnection(_connStr))
        {
            await conn.OpenAsync();
            var sql = "SELECT Id, Property1, Property2 FROM YourTableName WHERE IsNew = 1";
            using (var cmd = new SqlCommand(sql, conn))
            using (var reader = await cmd.ExecuteReaderAsync())
            {
                while (await reader.ReadAsync())
                {
                    items.Add(new YourModel
                    {
                        Id = reader.GetInt32(0),
                        Property1 = reader.GetString(1),
                        Property2 = reader.GetString(2)
                    });
                }
            }
        }
        return items;
    }

    public async Task MarkItemsAsProcessedAsync(IEnumerable<int> itemIds)
    {
        if (!itemIds.Any()) return;
        var idList = string.Join(",", itemIds);
        using (var conn = new SqlConnection(_connStr))
        {
            await conn.OpenAsync();
            var sql = $"UPDATE YourTableName SET IsNew = 0 WHERE Id IN ({idList})";
            using (var cmd = new SqlCommand(sql, conn))
                await cmd.ExecuteNonQueryAsync();
        }
    }
}

方案优缺点

  • 优点:实现简单,无需修改Web应用,依赖数据库自身功能即可完成同步。
  • 缺点:轮询间隔导致数据更新有延迟;频繁轮询增加数据库压力;多客户端场景需额外处理并发标记问题(如事务、行级锁)。

方案二:API接口实现

1. API端准备

若Web应用无法修改,需开发独立中间API服务,该服务可:

  • 定时轮询数据库或通过触发器+消息队列(如SQL Server Service Broker)捕获数据变化。
  • 提供REST接口供WPF查询新数据,或支持WebSocket推送实时更新。

2. WPF端实现

方式1:定时调用REST API

private async void PollingTimer_Tick(object sender, EventArgs e)
{
    try
    {
        var response = await _httpClient.GetAsync("https://your-api-url/api/new-items");
        if (response.IsSuccessStatusCode)
        {
            var newItems = await response.Content.ReadFromJsonAsync<List<YourModel>>();
            // 更新DataGrid逻辑同方案一
            await _httpClient.PostAsJsonAsync("https://your-api-url/api/mark-processed", newItems.Select(x => x.Id));
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine($"API调用出错:{ex.Message}");
    }
}

方式2:WebSocket实时推送

private async void InitializeWebSocket()
{
    using (var webSocket = new ClientWebSocket())
    {
        await webSocket.ConnectAsync(new Uri("wss://your-api-url/ws/data-updates"), CancellationToken.None);
        var buffer = new byte[1024 * 4];
        while (webSocket.State == WebSocketState.Open)
        {
            var result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
            if (result.MessageType == WebSocketMessageType.Text)
            {
                var json = Encoding.UTF8.GetString(buffer, 0, result.Count);
                var updatedItem = JsonSerializer.Deserialize<YourModel>(json);
                Application.Current.Dispatcher.Invoke(() =>
                {
                    var existingItem = DataGridItems.FirstOrDefault(x => x.Id == updatedItem.Id);
                    if (existingItem != null)
                    {
                        existingItem.Property1 = updatedItem.Property1;
                    }
                    else
                    {
                        DataGridItems.Add(updatedItem);
                    }
                });
            }
        }
    }
}

方案优缺点

  • 优点:解耦WPF与数据库,安全性更高(无需暴露连接字符串);WebSocket可实现实时更新;天然支持多客户端并发。
  • 缺点:需额外开发维护API服务,开发成本高于方案一;依赖API服务稳定性。

最优选择对比

维度数据库触发器+轮询API接口方案
开发成本低中/高(需开发API)
实时性延迟(取决于轮询间隔)可实时(WebSocket)
安全性低(暴露数据库连接)高(API隔离数据库)
并发支持需额外处理锁/事务天然支持多客户端
维护成本低中(需维护API服务)
  • 若开发资源有限、对实时性要求不高,优先选数据库触发器+轮询方案,快速落地需求。
  • 若对实时性要求高、需要多客户端支持、注重数据安全,优先选API接口方案,尤其是WebSocket推送方式。

现有代码适配说明

View层(DataGrid绑定)

确保DataGrid绑定到ViewModel的ObservableCollection:

<DataGrid ItemsSource="{Binding DataGridItems}" AutoGenerateColumns="False">
    <DataGrid.Columns>
        <DataGridTextColumn Header="属性1" Binding="{Binding Property1}" />
        <DataGridTextColumn Header="属性2" Binding="{Binding Property2}" />
    </DataGrid.Columns>
</DataGrid>

Model层

实现INotifyPropertyChanged确保属性更新同步到UI:

public class YourModel : INotifyPropertyChanged
{
    private int _id;
    private string _property1;
    private string _property2;

    public int Id
    {
        get => _id;
        set { _id = value; OnPropertyChanged(); }
    }

    public string Property1
    {
        get => _property1;
        set { _property1 = value; OnPropertyChanged(); }
    }

    public string Property2
    {
        get => _property2;
        set { _property2 = value; OnPropertyChanged(); }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 02:17:32