如何同步两个InkCanvas-es图纸?

时间:2011-12-20 16:13:45

标签: c# .net wpf xaml inkcanvas

我正在尝试开发一个在远程主机上显示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.EditingModeInkCanvasEditingMode.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);
        }
    }

请注意,异常总是被捕获。

这里的一般问题是:如何在集合中找到相同的笔画/点以便相应地删除它们?

2 个答案:

答案 0 :(得分:1)

我不确定你是否需要让它变得那么复杂,但这里只是一个WPF Markup解决方案,它应该完全符合你的需要:

http://msdn.microsoft.com/en-us/library/system.windows.controls.inkcanvas.aspx

请参阅API定义后的示例。如果使用LayoutTransform删除标记中的三行,它应该正是您所需要的。

如果你想在CodeBehind / VM中拥有StrokesCollection,那么将它作为DependencyProperty或VM属性绑定,然后你就可以了。

答案 1 :(得分:0)

问题在于StrokesCollection使用的序列化/反序列化机制。当double值被序列化并反序列化时,结果值会略有不同。

完整的代码示例和答案可以在这里找到:http://social.msdn.microsoft.com/Forums/en-AU/wpf/thread/9e1f43fa-6266-41b7-a5d0-7603f87ca58f