WPF MVVM模式下接收新的/更新后的Ink Strokes时如何更新UI
问题根因
你当前代码存在4个核心问题导致UI无法更新、数据传输异常:
Signature属性未实现属性变更通知,赋值后UI无法感知变更- 本地绘制保存
MemoryStream时未重置流位置,发送的是空数据 - 接收远程笔画更新后替换
StrokeCollection时,未重新绑定StrokesChanged事件,后续本地绘制无法触发发送逻辑 - 未加远程更新标记,接收远程数据后修改
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
相关产品推荐
相关产品推荐

