如何同步两个 InkCanvas-es 绘图?
我正在尝试开发一个在远程主机上显示 WPF InkCanvas 绘图的应用程序。基本上,它将本地 InkCanvas 与多个远程主机同步。我已经订阅了 StrokesChanged
事件:
this.DrawingCanvas.Strokes.StrokesChanged += this.Strokes_StrokesChanged;
以及处理程序。
private void Strokes_StrokesChanged(object sender, StrokeCollectionChangedEventArgs e)
{
if (e.Added != null && e.Added.Count > 0)
{
this.StrokeSynchronizer.SendAddedStroke(e.Added);
}
if (e.Removed != null && e.Removed.Count > 0)
{
this.StrokeSynchronizer.SendRemovedStroke(e.Removed);
}
}
当我绘制新曲线时,该事件仅调用一次。远程主机通过调用 this.RemoteInkCanvas.Strokes.Add(addedStrokes) 来正确绘制它。
当我通过 InkCanvasEditingMode.EraseByStroke 擦除曲线时,该事件也会调用一次,并且远程主机成功使用 this.RemoteInkCanvas.Strokes.Remove(removedStrokes) 。
问题来了!
当 this.DrawingCanvas.EditingMode
为 InkCanvasEditingMode.EraseByPoint
时,事件会调用一次,但有两个集合(添加和删除) )。这会导致远程主机变得疯狂。这是删除笔划的远程主机代码:
private StrokeCollection FindStrokesInLocalCollection(StrokeCollection receivedCollection)
{
var localStrokes = new StrokeCollection();
foreach (var erasedStroke in receivedCollection)
{
var erasedPoints = erasedStroke.StylusPoints;
foreach (var existentStoke in this.RemoteInkCanvas.Strokes)
{
var existentPoints = existentStoke.StylusPoints;
if (erasedPoints.SequenceEqual(existentPoints))
{
localStrokes.Add(existentStoke);
}
}
}
return localStrokes;
}
private void RemoteStrokeRemoved(StrokeCollection strokes)
{
try
{
// Simple this.RemoteInkCanvas.Strokes.Remove(strokes)
// does not work, because local and remote strokes are different (though equal) objects.
// Thus we need to find same strokes in local collection.
var strokesToRemove = this.FindStrokesInLocalCollection(strokes);
if (strokesToRemove.Count != strokes.Count)
{
Logger.Warn(string.Format(
"Whiteboard: Seems like remotely removed strokes were not found in local whiteboard. Remote count {0}, local count {1}.",
strokes.Count,
strokesToRemove.Count));
}
this.RemoteInkCanvas.Strokes.Remove(strokesToRemove);
}
catch (Exception ex)
{
Logger.Error("Whiteboard: Can not remove some strokes received from remote host.", ex);
}
}
请注意,异常总是会被捕获。
这里的一般问题是:如何在集合中找到相同的笔划/点以便相应地删除它们?
I am trying to develop an application which shows WPF InkCanvas drawings on remote host. Basically it synchronizes local InkCanvas with several remote hosts. I have subscribed to StrokesChanged
event:
this.DrawingCanvas.Strokes.StrokesChanged += this.Strokes_StrokesChanged;
And the handler.
private void Strokes_StrokesChanged(object sender, StrokeCollectionChangedEventArgs e)
{
if (e.Added != null && e.Added.Count > 0)
{
this.StrokeSynchronizer.SendAddedStroke(e.Added);
}
if (e.Removed != null && e.Removed.Count > 0)
{
this.StrokeSynchronizer.SendRemovedStroke(e.Removed);
}
}
When I am drawing a new curve the event invoked only once. The remote host draws it correctly by calling this.RemoteInkCanvas.Strokes.Add(addedStrokes)
.
When I am erasing a curve via InkCanvasEditingMode.EraseByStroke
the event also invoked once and remote host uses this.RemoteInkCanvas.Strokes.Remove(removedStrokes)
successfully.
Here goes the problem!
When the this.DrawingCanvas.EditingMode
is InkCanvasEditingMode.EraseByPoint
then the event invoked once but with two collections (Added and Removed). This causes remote hosts to get insane. Here is the remote host code which erases strokes:
private StrokeCollection FindStrokesInLocalCollection(StrokeCollection receivedCollection)
{
var localStrokes = new StrokeCollection();
foreach (var erasedStroke in receivedCollection)
{
var erasedPoints = erasedStroke.StylusPoints;
foreach (var existentStoke in this.RemoteInkCanvas.Strokes)
{
var existentPoints = existentStoke.StylusPoints;
if (erasedPoints.SequenceEqual(existentPoints))
{
localStrokes.Add(existentStoke);
}
}
}
return localStrokes;
}
private void RemoteStrokeRemoved(StrokeCollection strokes)
{
try
{
// Simple this.RemoteInkCanvas.Strokes.Remove(strokes)
// does not work, because local and remote strokes are different (though equal) objects.
// Thus we need to find same strokes in local collection.
var strokesToRemove = this.FindStrokesInLocalCollection(strokes);
if (strokesToRemove.Count != strokes.Count)
{
Logger.Warn(string.Format(
"Whiteboard: Seems like remotely removed strokes were not found in local whiteboard. Remote count {0}, local count {1}.",
strokes.Count,
strokesToRemove.Count));
}
this.RemoteInkCanvas.Strokes.Remove(strokesToRemove);
}
catch (Exception ex)
{
Logger.Error("Whiteboard: Can not remove some strokes received from remote host.", ex);
}
}
Please note, that the exception is always being caught.
The general question here: how to find same strokes/points in the collection in order to remove them accordingly?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我不确定您是否需要那么复杂,但这是一个仅 WPF 标记的解决方案,它应该完全满足您的需要:
http://msdn.microsoft.com/en-us/library/system.windows.controls.inkcanvas.aspx
请参阅以下示例API 定义。如果您使用 LayoutTransform 删除标记中的三行,它应该正是您所需要的。
如果您希望在 CodeBehind/VM 中拥有 StrokesCollection,则将其绑定为 DependencyProperty 或 VM 属性,然后就可以了。
I am not sure if you need to have it that complicated, but here's a WPF Markup only solution, which should exactly do what you need:
http://msdn.microsoft.com/en-us/library/system.windows.controls.inkcanvas.aspx
See the example after the API definitions. If you remove the three lines in the markup with the LayoutTransform it should be exactly what you need.
If you want to have the StrokesCollection in the CodeBehind/VM then bind it as a DependencyProperty or as a VM Property and you're set.
问题出在 StrokesCollection 使用的序列化/反序列化机制中。当双精度值被序列化和反序列化时,结果值会略有不同。
完整的代码示例和答案可以在这里找到:http://social.msdn.microsoft.com/Forums/en-AU/wpf/thread/9e1f43fa-6266-41b7-a5d0-7603f87ca58f
The problem is in serialization/deserialization mechanism used by StrokesCollection. When a
double
value is serialized and deserialized the resulting value slightly varies.The complete code sample and answer can be found here: http://social.msdn.microsoft.com/Forums/en-AU/wpf/thread/9e1f43fa-6266-41b7-a5d0-7603f87ca58f