65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 WPF 探索 Ink API

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.93/5 (57投票s)

2007年6月8日

10分钟阅读

viewsIcon

269820

downloadIcon

6528

使用 WPF 探索 Ink API

目录

引言

我不知道你们了解多少,但我对.NET 3.0越来越感兴趣,尤其是WPF。到目前为止,我主要通过结合使用Visual Studio 2005和WPF插件WPF的Visual Studio设计器,或者从其他地方(主要是Josh Smith的文章,谢谢Josh!),零散地借用代码片段来构建我的WPF应用程序,比如这篇文章这篇文章。总之,在这篇文章中,我决定使用Expression BLEND来尝试创作,看看效果如何以及它有多容易使用。

那么这次我决定做什么呢?我最近开始对Ink API产生浓厚兴趣,它有一个很棒的Tablet PC SDK。在我使用的Windows Vista中,相关的API是预装的,但如果你是XP用户,你可能需要下载SDK,这里提供下载:这里

不过,对于这篇文章来说,只要安装了.NET 3.0框架,我想这就足够了。

总之,正如我所说,我一直在玩Ink API,并对其进行了一些尝试。我一直在MSDN上研究它,然后(出于好奇)我查阅了Charles Petzold的书《Applications=Code+Markup》,发现我试图做的事情与他非常相似,所以这个应用程序可以看作是我和他书本示例的结合。我决定制作最简单的Paint版本,没有任何图层或花哨的功能,只有Ink。

所以这个应用程序将演示Ink的使用方面:

  • 保存墨迹
  • 将墨迹保存为位图
  • 加载墨迹
  • 剪切墨迹
  • 复制墨迹
  • 粘贴墨迹
  • 删除墨迹
  • 选择墨迹
  • 格式化墨迹
  • 笔尖颜色
  • 更改笔尖类型
  • 更改笔

哦,它还将演示以下WPF控件的使用,但不会详述(如果你想了解它们如何工作,请深入研究XAML):

  • 按钮
  • Grids
  • InkCanvas
  • GroupBox
  • RadioBtton
  • Expander
  • 弹出窗口

它显然使用Styles和Templates来实现其美观的外观,但这些WPF概念在其他地方已有描述,你可以尝试这里Josh Smith,他在他关于WPF的美丽系列文章中对此进行了阐述。

本文将讨论Ink的使用,如果认为重要,将解释与特定Ink操作相关的UI元素。

关于演示应用程序的一点说明

在我开始用附带的WPF应用程序的内部机制轰炸大家之前,我们先快速看一下最终产品。

他是不是很漂亮?

该应用程序基于Visual Studio 2005,并安装了WPF的Visual Studio设计器,并结合了Expression BLEND和Visual Studio 2005。我想指出的是,我认为仅使用Expression BLEND并不能让你成为WPF高手,如果你想要写出漂亮的 कोड,你仍然需要能够手工编写代码。但正如我所说,我只是想在本文中尝试一下。而且我不得不说,我认为Expression BLEND团队做得非常出色,它和Adobe Flash一样易于使用,我也非常喜欢Adobe Flash。

必备组件

  1. 显然,因为是WPF,你还需要.NET 3.0框架
  2. 如果你真的想在Visual Studio中编辑内容,那么WPF的Visual Studio设计器可能会派上用场。

那么它到底能做什么?

正如我上面所说,该应用程序具有以下功能,我们将逐一研究这些项目。

  • 保存墨迹
  • 将墨迹保存为位图
  • 加载墨迹
  • 剪切墨迹
  • 复制墨迹
  • 粘贴墨迹
  • 删除墨迹
  • 选择墨迹
  • 格式化墨迹
  • 笔尖颜色
  • 更改笔尖类型
  • 更改笔

但在我们深入研究所有这些之前,我们需要理解一件事,那就是,我们实际上将所有这些相关功能应用到了什么上面?

在这个例子中,我将使用Microsoft.Ink命名空间,特别是将演示使用WPF的InkCanvas 控件。当然,它是一个WPF控件,但Tablet PC SDK中也有等效的控件,但我如上所述,我使用的是InkCanvas 控件。

WPF的InkCanvas 控件公开了一个有趣的类,我们将在本文中反复使用它。这个类是StrokeCollection,可以通过InkCanvas类访问。通过使用这两个类,我们可以完成创建这个非常简单的Paint应用程序的所有相关任务。

那么,我们开始吧,好吗?

保存墨迹

保存Ink非常简单,我们只需使用InkCanvas.Strokes对象的Save()方法。它接受任何流。在附带的应用程序中,我创建了一个名为“Ink Serialized Format”的新文件格式,但你可以使用任何你喜欢的格式。

 this.inkCanv.Strokes.Save(file); 

这就足以保存所有必要的信息,以便稍后恢复Ink。

将墨迹保存为位图

将Ink保存为位图要棘手一些,但并非不可能。我们只需使用RenderTargetBitmapBmpBitmapEncoderBitmapFrame这三个很棒的类,如下所示。

int marg = int.Parse(this.inkCanv.Margin.Left.ToString());
RenderTargetBitmap rtb = 
        new RenderTargetBitmap((int)this.inkCanv.ActualWidth - marg,
                (int)this.inkCanv.ActualHeight - marg, 0, 0, 
            PixelFormats.Default);
rtb.Render(this.inkCanv);
BmpBitmapEncoder encoder = new BmpBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(rtb));
encoder.Save(file);
file.Close();

需要注意的是,这是一个单向过程,我没有找到一种方法可以从图像中检索Ink。尽管如此,将图像添加为InkCanvas层次结构中的节点并没有问题。这将在本文系列的第二部分中进一步讨论。

加载Ink文件

毫不奇怪,从文件加载Ink就是保存文件的反向操作。和以前一样,我们只需要使用流。在附带的应用程序中,我创建了一个名为“Ink Serialized Format”的新文件格式,但你可以使用任何你喜欢的格式。

this.inkCanv.Strokes = new StrokeCollection(file);

剪切墨迹

要实际剪切Ink,你必须先选择要剪切的Ink。这可以通过两种方式完成:你可以使用“选择”按钮(将在这里讨论),或者可以将当前笔尖更改为选择模式。这将在这里更详细地讨论。

目前,我假设至少有一些Ink被选中。你可以看到选中的Ink,因为它会有一个围绕Ink的边界框和调整大小的句柄,如上图所示。所以一旦你选择了一些Ink,你就可以剪切它;这非常容易。

if (this.inkCanv.GetSelectedStrokes().Count > 0)
    this.inkCanv.CutSelection();

复制墨迹

复制Ink几乎与剪切Ink相同(假设你已经选中了一些Ink),我们只需使用InkCanvasCopySelection方法而不是CutSelection

if (this.inkCanv.GetSelectedStrokes().Count > 0)
    this.inkCanv.CopySelection();

粘贴墨迹

粘贴Ink也同样容易(假设你已经选中了一些Ink),让我们来看看。

if (this.inkCanv.CanPaste())
    this.inkCanv.Paste();

删除墨迹

删除Ink也非常简单(假设你已经选中了一些Ink),只需检查是否有Strokes可以移除,然后移除它们。

if (this.inkCanv.GetSelectedStrokes().Count > 0)
{
    foreach (Stroke strk in this.inkCanv.GetSelectedStrokes())
        this.inkCanv.Strokes.Remove(strk);
}

选择墨迹

回想一下,对于选择、剪切、复制、粘贴和删除操作,我们必须实际选中Ink。那么我们如何选择Ink呢?正如我所说,这可以通过两种方式完成:你可以使用“选择”按钮(此选项),或者可以将当前笔尖更改为选择模式。所以让我们来看看如何选择所有Ink。这非常容易。

this.inkCanv.Select(this.inkCanv.Strokes);

格式化墨迹

格式化Ink取决于你是否首先选中了要格式化的Ink。所以假设你选中了一些Ink(Strokes),当你使用“格式化Ink”按钮时,你将看到颜色选择器窗口,如下面的“笔尖颜色”部分所示。该窗口将允许你更改Strokes的属性。

注意:当选择笔画时,选中的笔画看起来会像这样。

“格式化”按钮的代码将简单地尝试获取第一个笔画的颜色,然后显示对话框窗口,我们可以在其中为选定的Strokes选择新颜色。

StylusSettings dlg = new StylusSettings();
dlg.Owner = this;

// Try getting the DrawingAttributes of the first selected stroke.
StrokeCollection strokes = this.inkCanv.GetSelectedStrokes();

if (strokes.Count > 0)
    dlg.DrawingAttributes = strokes[0].DrawingAttributes;
else
    dlg.DrawingAttributes = this.inkCanv.DefaultDrawingAttributes;

if ((bool)dlg.ShowDialog().GetValueOrDefault())
{
    // Set the DrawingAttributes of all the selected strokes.
    foreach (Stroke strk in strokes)
        strk.DrawingAttributes = dlg.DrawingAttributes;
}

笔尖颜色

为了让用户控制Ink的颜色和绘制方式,有一个第二个XAML窗口,名为“StylusSettings.xaml”,它包含一个UniformGrid控件,其中包含按钮,这些按钮的背景只是设置为System.Brushes集合中的特定Brush颜色。

System.Brushes的迭代是通过反射完成的。

private void createGridOfColor()
{
    PropertyInfo[] props = typeof(Brushes).GetProperties(BindingFlags.Public |
                                          BindingFlags.Static);
    // Create individual items
    foreach (PropertyInfo p in props)
    {
        Button b = new Button();
        b.Background = (SolidColorBrush)p.GetValue(null, null);
        b.Foreground = Brushes.Transparent;
        b.BorderBrush=Brushes.Transparent;
        b.Click += new RoutedEventHandler(b_Click);
        this.ugColors.Children.Add(b);
    }
}

此页面还负责显示和设置当前用于绘制的Ink值。这是通过一个名为DrawingAttributes的类实现的,该类可以从InkCanvas中检索和设置。

public DrawingAttributes DrawingAttributes
{
    set
    {
        chkPressure.IsChecked = value.IgnorePressure;
        chkHighlight.IsChecked = value.IsHighlighter;
        penWidth = value.Width;
        penHeight = value.Height;
        currColor = value.Color;
    }
    get
    {
        DrawingAttributes drawattr = new DrawingAttributes();
        drawattr.IgnorePressure = (bool)chkPressure.IsChecked;
        drawattr.Width=penWidth;
        drawattr.Height = penHeight;
        drawattr.IsHighlighter = (bool)chkHighlight.IsChecked;
        drawattr.Color = currColor;
        return drawattr;
    }
}

更改笔尖类型

还可以更改笔尖控制,可选项如下:

  • Ink:将绘制Ink
  • Erase:将擦除Ink(用笔尖覆盖的部分)
  • Erase By Stroke:将擦除选定的Stroke
  • Select:允许用户绘制框以选择Ink

允许用户绘制Ink。

允许用户擦除Ink。

允许用户擦除Ink笔画。

允许用户选择Ink笔画。

更改笔的大小

还可以更改笔的大小。

其他一些很酷的东西

有一些区域我相当喜欢,希望你们也会觉得有趣,例如:

  • FishEyePanel.cs:这不是我自己的代码,但我仍然很喜欢。它来自这里,作者是Paul Tallett。基本上,它的工作原理类似于Apple漂亮的工具栏,鼠标附近的图标最大,两侧的图标依次变小,以此类推。

就是这样

我希望这篇文章能说明在你的应用程序中使用Ink是多么容易。也就是说,我只触及了Tablet PC SDK可以做什么的一小部分。我不想在人们完全了解Ink的巨大内部工作原理之前就吓跑他们,而是让他们先看到一个相对简单的应用。我计划写另一篇关于Ink的文章,希望能将其更紧密地结合起来,所以你可能需要等到那时。

那么你觉得呢?

我想请问,如果你喜欢这篇文章,请投票并留下评论,这能让我知道文章是否达到了合适的水平,以及是否包含了人们需要知道的内容。

结论

我很高兴写了这篇文章,正如我所说,我将再写一篇关于Ink的文章,但很抱歉,那将是Vista独有的。它还将使用另一种.NET 3.0技术。我希望下一篇文章对各位好朋友来说会相当有趣,因为它将使用两种.NET 3.0技术和Vista独有的API。

正如我之前所说……如果你想保持工作/生活平衡,我建议你尽量远离WPF,因为一旦它把你拖入它的触角,你就真的无处可逃了。“抵抗是徒劳的。你们将被同化。”

历史

  • v1.0 2007/06/06:初始发布

其他

我鼓励大家深入学习WPF,阅读Josh Smith的所有文章,并尝试自己使用Expression BLEND。正如我所说,我认为它很酷,但在某些地方也应该与手工编码结合使用。如果你对WPF是认真的,你应该多阅读这方面的内容,以便了解Expression BLEND生成的代码实际上做了什么。

© . All rights reserved.