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

WPF MVVM模式下接收新的/更新后的Ink Strokes时如何更新UI

问题根因

你当前代码存在4个核心问题导致UI无法更新、数据传输异常:

  1. Signature属性未实现属性变更通知,赋值后UI无法感知变更
  2. 本地绘制保存MemoryStream时未重置流位置,发送的是空数据
  3. 接收远程笔画更新后替换StrokeCollection时,未重新绑定StrokesChanged事件,后续本地绘制无法触发发送逻辑
  4. 未加远程更新标记,接收远程数据后修改StrokeCollection会触发本地发送逻辑,造成循环发送

修改步骤

1. 改造Signature属性,添加变更通知

给Signature添加带属性通知的get/set,同时自动处理StrokesChanged事件的绑定解绑:

class MainViewModel : INotifyPropertyChanged
{
    // 新增私有字段存储StrokeCollection
    private StrokeCollection _signature;
    // 新增远程更新标记,避免循环发送
    private bool _isRemoteUpdate = false;

    // 改造后的Signature属性
    public StrokeCollection Signature
    {
        get => _signature;
        set
        {
            _signature = value;
            OnPropertyChanged(nameof(Signature));
            // 自动绑定新集合的StrokesChanged事件
            _signature.StrokesChanged -= Signature_StrokesChanged;
            _signature.StrokesChanged += Signature_StrokesChanged;
        }
    }

    // 新增属性通知触发方法(如果你已经有同名方法可以不用重复加)
    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    // ... 其余原有代码保持不变
}

2. 修正本地笔画发送逻辑

修改Signature_StrokesChanged方法,添加远程更新判断,同时重置MemoryStream位置:

public void Signature_StrokesChanged(object sender, StrokeCollectionChangedEventArgs e)
{
    // 远程更新触发的笔画变更不发送,避免循环
    if (_isRemoteUpdate) return;

    MemoryStream _ms = new MemoryStream();
    Signature.Save(_ms);
    // 重置流位置到起始点,否则发送的是空数据
    _ms.Position = 0;
    _server.SendInkStrokesToServer(_ms);
}

3. 修正远程笔画接收更新逻辑

修改InkStrokeReceived方法,添加远程更新标记,避免触发本地发送:

private void InkStrokeReceived()
{
    Application.Current.Dispatcher.Invoke(() =>
    {
        // 标记为远程更新
        _isRemoteUpdate = true;
        var ink = _server.PacketReader.ReadInkStroke();
        using MemoryStream memoryStream = new MemoryStream(ink);
        // 直接修改现有集合,避免频繁重建对象
        Signature.Clear();
        Signature.Add(new StrokeCollection(memoryStream));
        // 恢复标记
        _isRemoteUpdate = false;
    });
}

4. 修正XAML绑定与拆包逻辑

  • 给InkCanvas的Strokes绑定添加双向绑定模式:
<InkCanvas          
    Name="inkCanv" 
    Grid.Column="1" 
    Grid.Row="1" 
    Height="130" 
    Background="Azure"
    Strokes="{Binding Signature, Mode=TwoWay}"
    >
</InkCanvas>
  • 修正ReadInkStroke的拆包逻辑,避免TCP粘包/拆包导致数据不完整:
public byte[] ReadInkStroke()
{
    var length = ReadInt32();
    byte[] inkBuffer = new byte[length];
    int totalRead = 0;
    // 循环读满指定长度的数据,避免单次读取不完整
    while (totalRead < length)
    {
        int read = _ns.Read(inkBuffer, totalRead, length - totalRead);
        if (read == 0) throw new IOException("连接已断开");
        totalRead += read;
    }
    return inkBuffer;
}

以上修改完成后,本地绘制可以正常发送,接收远程笔画后UI会自动更新,且不会出现循环发送、数据为空的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 08:15:04