在 Visual Studio LightSwitch中,从扫描仪和摄像头获取图像

分享于 

31分钟阅读

Web开发

  繁體
PhotoManagerLS.jpg

介绍

使用 Microsoft Visual Studio LightSwitch 2011,你可以构建各种适用于数据的应用程序。 现代业务应用程序通常需要包括图像来表示产品。联系人或者许多其他数据项。 在LightSwitch中,你可以轻松地将图片存储到 Image 类型的实体属性。 这是一种新的业务类型,允许上传到像Jpeg和Png类型的应用程序图像文件的数据库。 图片可以来自磁盘上的文件,而LightSwitch提供了一个方便的Image Editor 控件,可以上传它们,也可以从扫描仪和网络摄像机。 本文将学习如何使用 Silverlight 4中提供的特性扩展LightSwitch应用程序,并使它的能够与图像采集设备一起使用。 你将创建一个名为照片管理器的应用程序,帮助你跟踪磁盘上的图片,但也允许从设备上捕获图像。 Visual Studio 2010 Professional或者更高版本需要在同一解决方案中创建自定义控件。

背景

本文解释的样例应用程序将只由一个名为 Photo的实体组成,该实体代表一个。 将创建三个屏幕,用于将图像添加到集合和搜索屏幕以及可以编辑网格屏幕( 这使得编辑现有图像条目更加容易)的数据输入屏幕。 数据输入屏幕允许从扫描仪和摄像头中捕获图像,而不是从磁盘选择映像文件。 因为这需要使用特定的api来使用摄像头,所以需要对 Silverlight 4有一点熟悉,但是为了使用WIA自动化( Silverlight 4中的新增功能),使用了com自动化。 通过使用 WIA,可以调用系统的操作 API,允许使用此类设备。 一旦图像从扫描仪或者网络摄像头获取,他们必须转换为一种格式,可以接受 Silverlight 4. 为此,我们使用一个开源库 CodePlex .NET 映像工具 for。 这个库提供了许多对象,可以轻松处理 Silverlight 4中的图像,避免重新创建轮子,从而节省了大量时间。 下载后,将zip归档文件提取到磁盘上的文件夹,以便以后能够轻松地添加引用。 由于应用程序使用了com自动化,所以本文所描述的权限和功能仅在应用程序作为桌面客户端运行时可用。 这里要显示很多,所以我假设你熟悉 Visual Studio 开发环境中的概念,如创建解决方案。项目等。

LightSwitch

我们首先创建一个与设备一起工作的Silverlight 4类库,并公开一个用于网络摄像头的自定义控件。 这样的控件将在应用程序中的数据输入屏幕中添加,利用扩展性。 你将基本上有一个包含Silverlight类库和一个具有对它的他项目的引用的vmkernel应用程序的解决方案。

创建Silverlight类库和扫描仪服务

在 Visual Studio 2010中要做的第一件事是创建一个名为 PhotoManager的空白解决方案。 接下来,你可以添加名为类库的新项目,如下图所示:

LSPhotoMan1.jpg

Visual Studio 将要求你为类库指定Silverlight版本,选择 Silverlight,并继续。 此时,你将看到在项目中添加了一个默认类。 在解决方案资源管理器中,右击代码文件 NAME ( 根据选择的编程语言,Class1.vb Class1.cs ),然后选择重命名。 类的新 NAME 将为 ScannerService。 编写代码之前,需要添加对图像工具库的下列程序集的引用:

  • ImageTools.dll
  • ImageTools.Utils.dll
  • ImageTools.IO.Jpeg.dll
  • ImageTools.IO.Bmp.dll

其他程序集可以用于将图片编码和解码到不同的文件格式,但这些格式已经足够。 让我们把焦点放在 ScannerService 类上。 这个方法将实现一个名为 Scan的方法,调用com自动化in从 Windows 访问 WIA api,并将扫描过程的结果存储在磁盘上,并将扫描过程存储到一个类型为 System.Byte()的属性中。 一个字节 array 实际上是LightSwitch接受图像的方式。 此外,类还需要实现 INotifyPropertyChanged 接口。 通过这种方法,当属性的值发生变化时,会发送一个通知给客户机,并将更新 Image Editor 或者 Image Viewer 控件。 让我们从写这个开始:

OptionStrictOffImports System.Runtime.InteropServices.AutomationImports System.Windows.Media.ImagingImports System.Runtime.CompilerServicesImports System.Windows.ThreadingImports System.IOImports ImageToolsImports ImageTools.IO.JpegImports ImageTools.IO.PngImports ImageTools.IOImports System.ComponentModelImports ImageTools.IO.BmpPublicClass ScannerService
 Implements INotifyPropertyChanged
 '''''' Fired when the image acquisition completes successfully''''''<remarks>PublicEvent AcquisitionCompleted()
 '''''' Fired when the image acquisition fails for some reasons''''''<remarks>PublicEvent AcquisitionFailed()
 ProtectedSub OnPropertyChanged(ByVal strPropertyName AsString)
 IfMe.PropertyChangedEvent IsNotNothingThenRaiseEvent PropertyChanged_
 (Me, New System.ComponentModel.PropertyChangedEventArgs(strPropertyName))
 EndIfEndSubPublicEvent PropertyChanged(sender AsObject, _
 e As System.ComponentModel.PropertyChangedEventArgs) _
 Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
 Private _acquiredImage AsByte()
 '''''' Returns the acquired image under a form that is accepted ''' by the LightSwitch Image control''''''<value>Byte()</value>'''<returns>'''<remarks>PublicProperty AcquiredImage AsByte()
 GetReturn _acquiredImage
 EndGetSet(value AsByte())
 _acquiredImage = value
 OnPropertyChanged("AcquiredImage")
 EndSetEndProperty

当需要使用com自动化时,请记住 Option Strict Off 指令中需要指令。 注意,还有两个事件是如何公开的,只是通知扫描进程( 已经完成或者失败)的进度。 下一步是编写 Scan 方法,你将看到调用后面解释的其他方法:

'''''' Acquires an image from scanner. Stores the result in the'''<seealsocref="acquiredimage"> property and returns the pathname for the image file''''''<returns>String</returns>'''<remarks>Available only if the application is running out-of-browser</remarks>PublicFunction Scan() AsString'If not out-of-browser:If AutomationFactory.IsAvailable = FalseThenRaiseEvent AcquisitionFailed()
 ReturnNothingEndIf'Gets a reference to the WIA dialogTryDim commonDialog AsObject = AutomationFactory.CreateObject("WIA.CommonDialog")
 'Show the dialog for scanning inmagesDim imageFile AsObject = commonDialog.ShowAcquireImage()
 'If the result is not null,If imageFile IsNotNothingThen'Saves the result as an image to diskDim filePath AsString = BuildFileName()
 imageFile.SaveFile(filePath)
 commonDialog = Nothing'Converts the image file into a byte arrayMe.AcquiredImage = ConvertImageToByteArray(filePath)
 RaiseEvent AcquisitionCompleted()
 Return filePath
 ElseRaiseEvent AcquisitionFailed()
 ReturnNothingEndIfCatch ex As Exception
 ThrowEndTryEndFunction

如果应用程序作为桌面客户端运行,则 AutomationFactory 类允许理解。 如果未作为桌面客户端( IsAvailable = False ) 运行,则代码将引发 AcquisitionFailed 事件并返回 null 对象。 这实际上是一个双重检查,因为这可以在vmkernel客户机中完成,但是如果另一个开发人员忘记添加检查。 如果是桌面客户端,那么代码通过 AutomationFactory.CreateObject 方法创建 WIA.CommonDialog 对象的实例,然后调用它的ShowAcquireImage 方法来显示默认的图像获取对话框。 请注意代码如何将图像保存到磁盘( 记住,它存储为位图)。 BuildFileName 是一种基于当前日期/时间构造增量文件名的方法。 保存后,代码将获取的结果分配给 AcquiredImage 属性。 通过将磁盘上的文件通过称为 ConvertImageToByteArray的方法转换为字节 array 来实现这一点。 下面的代码演示如何构造增量文件名:

'''''' Constructs a file name starting from today's date and time''''''<returns>'''<remarks>PrivateFunction BuildFileName() AsStringDim tempString AsNew Text.StringBuilder
 tempString.Append(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments))
 tempString.Append("")
 tempString.Append(Date.Now.Year.ToString)
 tempString.Append(Date.Now.Month.ToString)
 tempString.Append(Date.Now.Day.ToString)
 tempString.Append("_")
 tempString.Append(Date.Now.Hour.ToString)
 tempString.Append(Date.Now.Minute.ToString)
 tempString.Append(Date.Now.Second.ToString)
 tempString.Append(".bmp")
 Return GetUniqueFilename(tempString.ToString)EndFunctionPrivateFunction GetUniqueFilename(ByVal fileName AsString) AsStringDim count AsInteger = 0'a counterDim name AsString = String.Empty
 'If the original file name does not exist...If System.IO.File.Exists(fileName) Then'Get details about the file nameDim currentFileInfo AsNew System.IO.FileInfo(fileName)
 'if it has extension...IfNotString.IsNullOrEmpty(currentFileInfo.Extension) Then'takes the file name without extension name = currentFileInfo.FullName.Substring_
 (0, currentFileInfo.FullName.LastIndexOf("."c))
 Else'otherwise uses the current file name name = currentFileInfo.FullName
 EndIf'Iterates until the file name existsWhile System.IO.File.Exists(fileName)
 count += 1 fileName = name + "_" + count.ToString() + currentFileInfo.Extension
 EndWhileEndIfReturn fileNameEndFunction

BuildFileName 只是根据当前日期/时间构建一个文件 NAME。 为了避免重复,调用了一个称为 GetUniqueFileName的附加方法。 这确保磁盘上不存在给定文件;如果存在,则通过附加递增号生成新文件 NAME,直到确保文件的惟一性。 下面是 ConvertImageToByteArray 方法的代码:

'''''' Converts an image file into a Byte array, which is accepted in LightSwitch'''PrivateFunction ConvertImageToByteArray(fileName AsString) AsByte()
 Dim bm AsNew BmpDecoder()
 Dim inputImg AsNew ExtendedImage
 Using fs1 AsNew FileStream(fileName, FileMode.Open)
 bm.Decode(inputImg, fs1)
 Dim enc AsNew JpegEncoder
 Using ms AsNew MemoryStream
 enc.Encode(inputImg, ms)
 Return ms.ToArray()
 EndUsingEndUsingEndFunction

这种方法至关重要:从指向先前捕获的图像文件的FileStream 对象开始,它使用图像工具库中的BmpDecoder.Decode 方法将流解码为 ExtendedImage 类型,该对象也被库公开。 接下来假设要使用Jpeg格式,使用 JpegEncoder.Encode 方法将位图的内容写在Jpeg图像的形式下面。 把这个写到 MemoryStream 很重要,因为这个对象公开了一个方法调用 ToArray,它转换为一个字节。 这就是LightSwitch可以将它的存储到 Image 类型的属性。 最后一步是在类的构造函数中填充编码器和解码器集合,如下所示:

PublicSubNew()
 Decoders.AddDecoder(Of JpegDecoder)()
 Decoders.AddDecoder(Of BmpDecoder)()
 Encoders.AddEncoder(Of BmpEncoder)()
 Encoders.AddEncoder(Of JpegEncoder)()EndSub

扫描仪服务类已经完成。 下一步是构建一个自定义控件,该控件将在LightSwitch屏幕中使用,以捕获来自摄像头的图像。

创建一个自定义控件来进行网络摄像机交互

为项目选择项目添加新项目以添加新的Silverlight用户控件到项目。 你可以像下图中那样选择的Silverlight用户控件模板:

LSPhotoMan2.jpg

基本上,该控件将提供用户界面来从可用设备列表中选择摄像头,并允许启动和停止视频捕获。 用户界面的XAML代码如下所示:

<UserControlx:Class="DelSole.PhotoService.WebcamControl"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"mc:Ignorable="d"d:DesignHeight="300"d:DesignWidth="480"><!--Dividing the main grid into three columns--><Gridx:Name="LayoutRoot"Background="White"><Grid.ColumnDefinitions><ColumnDefinitionWidth="200"/><ColumnDefinition/></Grid.ColumnDefinitions><BorderCornerRadius="6"BorderBrush="Black"BorderThickness="2"><StackPanel><TextBlockText="Available video devices:"Foreground="Blue"FontWeight="SemiBold"/><ListBoxName="VideoDevicesListBox"ItemsSource="{Binding}"Margin="0,10,0,0"><ListBox.ItemTemplate><DataTemplate><!-- This is data bound to the FriendlyName property
 of the collection of video devices--><TextBlockText="{Binding FriendlyName}"/></DataTemplate></ListBox.ItemTemplate></ListBox></StackPanel></Border><!--This last StackPanel nests the box for showing the
 webcam output and for showing the still images collection--><StackPanelGrid.Column="1"><!--This rectangle will show the actual webcam output--><BorderBorderBrush="Black"BorderThickness="2"CornerRadius="6"><RectangleWidth="320"Height="240"Name="WebcamBox"/></Border><BorderBorderBrush="Black"BorderThickness="2"CornerRadius="6"><StackPanelOrientation="Horizontal"><StackPanel.Resources><!--Defines a common set of properties for each button--><Stylex:Key="ButtonStyle"TargetType="Button"><SetterProperty="Width"Value="80"/><SetterProperty="Height"Value="30"/><SetterProperty="Margin"Value="5"/></Style></StackPanel.Resources><ButtonName="StartButton"Content="Start"Style="{StaticResource ButtonStyle}"/><ButtonName="StopButton"Content="Stop"Style="{StaticResource ButtonStyle}"/><ButtonName="ShotButton"Content="Get picture"Style="{StaticResource ButtonStyle}"/></StackPanel></Border></StackPanel></Grid></UserControl>

除了许多按钮,每个按钮都用于特定的自解释操作,注意 ListBox 控件是如何绑定的,并在运行时填充。 模板的ListBox 数据包括一个 TextBlock 控件,该控件绑定到在后面的代码中解释的可以用设备的FriendlyName 属性。 此时,设计器应该像下面的图形所示:

LSPhotoMan3.jpg

从透视图背后,你现在实现的成员类似于你在扫描仪服务类中看到的。 主要区别在于表示图像的属性是依赖项属性,因为在使用自定义控件并提供最佳数据绑定支持时,这是合适的。 这是代码的第一部分:

Imports ImageTools.IOImports ImageTools.IO.JpegImports System.IO, ImageTools.ImageExtensionsImports ImageTools.IO.PngPartialPublicClass WebcamControl
 Inherits UserControl
 '''''' Fired when the Webcam completes capturing an image to a WriteableBitmap object''''''<remarks>PublicEvent CaptureCompleted()
 PrivateWithEvents capSource As CaptureSource
 Private capturedImageProperty As DependencyProperty = _
 DependencyProperty.Register("CapturedImage", _
 GetType(Byte()), GetType(WebcamControl), Nothing)
 '''''' Returns the still image taken from the Webcam under a form ''' that is accepted by the LightSwitch Image Editor control''''''<value>'''<returns>Byte()</returns>'''<remarks>PublicReadOnlyProperty CapturedImage AsByte()
 GetReturnCType(GetValue(capturedImageProperty), Byte())
 EndGetEndPropertyPublicSubNew()
 InitializeComponent()
 Encoders.AddEncoder(Of JpegEncoder)()
 Decoders.AddDecoder(Of JpegDecoder)()
 Encoders.AddEncoder(Of PngEncoder)()
 EndSub

请注意 CaptureSource 类型的文件是如何定义的。 这是 Silverlight 4中的一个对象,代表所选的摄像头设备。 一旦加载了用户控件,这个类的实例就会被创建,这也是用可以用设备列表填充 ListBox的点:

PrivateSub SilverlightWebcamControl_Loaded_
(sender AsObject, e As System.Windows.RoutedEventArgs) HandlesMe.Loaded
 'Retrieves the list of available video devicesMe.VideoDevicesListBox.ItemsSource = _
CaptureDeviceConfiguration.GetAvailableVideoCaptureDevices()
 'Creates a new capture sourceMe.capSource = New CaptureSource()EndSub

iPhone 7 还没出来,我们已经在iPhone上获取细节 8,或者不管是想到下一步。 CaptureDeviceConfiguration.GetAvailableVideoCaptureDevices 返回 VideoCaptureDevice 对象的ReadonlyCollection,每个对象代表一个摄像头。 此时,你可以开始处理 Button.Click 事件。 首先,启动和停止(。查看代码中的注释):

PrivateSub StartButton_Click(sender As System.Object, _
e As System.Windows.RoutedEventArgs) Handles StartButton.Click
 IfMe.capSource IsNotNothingThen'If a device is already capturing, then stop itMe.capSource.Stop()
 'Set capture devices taking selected items from ListBoxesMe.capSource.VideoCaptureDevice = _
 DirectCast(VideoDevicesListBox.SelectedItem, VideoCaptureDevice)
 'Creates a VideoBrush for showing video outputDim webcamBrush AsNew VideoBrush()
 webcamBrush.SetSource(Me.capSource)
 'Fills the rectangle with the video source WebcamBox.Fill = webcamBrush
 'It's a good idea requesting user permission before starting captureIf CaptureDeviceConfiguration.AllowedDeviceAccess _
 OrElse CaptureDeviceConfiguration.RequestDeviceAccess() ThenMe.capSource.Start()
 EndIfEndIfEndSubPrivateSub StopButton_Click(sender As System.Object, _
e As System.Windows.RoutedEventArgs) Handles StopButton.Click
 Me.capSource.Stop()EndSub

为了从选定的网络摄像头获取静态图像,你可以调用 CaptureSource.CaptureImageAsync 方法,然后处理 CaptureSource.CaptureImageCompleted 若要将获取的图像转换为字节 array,请执行以下操作:

PrivateSub ShotButton_Click(sender As System.Object, _
e As System.Windows.RoutedEventArgs) Handles ShotButton.Click
 IfMe.capSource IsNotNothingThenTry'Captures a still imageMe.capSource.CaptureImageAsync()
 Catch ex As InvalidOperationException
 MessageBox.Show("You need to start capture first")
 Catch ex As Exception
 EndTryEndIfEndSubPrivateSub capSource_CaptureImageCompleted(ByVal sender AsObject,
 ByVal e As System.Windows.Media.
 CaptureImageCompletedEventArgs) Handles capSource.CaptureImageCompleted
 Try'Gets the instance of the captured imageDim converted = e.Result.ToImage
 'Encodes the image to JpegDim encoder AsNew JpegEncoder()
 'Converts the image to a byte array, which is accepted by LightSwitchUsing ms AsNew MemoryStream
 encoder.Encode(converted, ms)
 Me.SetValue(Me.capturedImageProperty, ms.ToArray)
 EndUsingRaiseEvent CaptureCompleted()
 Catch ex As Exception
 Throw e.ErrorEndTryEndSub

注意在事件处理程序中如何通过 ToImage 扩展方法将捕获的图像( e.Result ) 转换为 ExtendedImage 对象,从图像工具库中获取。 然后按照你之前对扫描仪服务类所看到的方式进行编码。 记住,LightSwitch同时支持Jpeg和Png图像格式,所以你并不局限于 JpegEncoder。 现在是在LightSwitch客户机应用程序中使用这个类库的时候了。 进入下一节之前,构建项目并确保不会产生错误。

创建LightSwitch应用程序

此时,你可以通过选择 LightSwitch应用程序模板来向解决方案添加新的LightSwitch项目,如下图所示:

LSPhotoMan4.jpg

新项目就绪后,单击创建新表。 定义一个名为 Photo的新实体,具有三个属性: Picture ( 必需的,类型为 Image ),Description ( 类型为 String ) 和 DateTaken ( 类型为 Date ):

LSPhotoMan5.jpg

现在,你将添加三个屏幕设计器( 使用工具栏上的屏幕按钮): 一个名为,的数据入口屏幕,一个叫做搜索照片的搜索屏幕和一个可以编辑的网格。 为了提供一个示例,这是你添加数据输入屏幕的方式:

LSPhotoMan6.jpg

对于数据输入屏幕,这是将添加自定义Silverlight控件和两个按钮启动扫描仪服务的地方。 ,在解决方案资源管理器中双击 Create Photo然后在 Rows Layout 元素下展开down这样你就可以选择自定义控件命令,如下图所示:

LSPhotoMan7.jpg

此时将显示添加自定义控件对话框。 单击添加引用,然后添加对以前创建的Silverlight类库项目的引用,最后选择 WebcamControl 元素:

LSPhotoMan8.jpg

由于不实际将任何数据源绑定到控件,因此你可以保持数据绑定路径不变。 添加控件后,在属性窗口中,取消选中 Is Visible 复选框。 这是因为用户将决定什么时候打开控件以通过摄像头获取图片。 现在你可以添加两个按钮;确保屏幕命令栏已经展开,然后选择 Add Add new按钮。 为新按钮指定一个 NAME,例如 AcquireFromScanner:

LSPhotoMan9.jpg

重复相同的步骤添加另一个名为 AcquireFromWebcam的按钮。 添加了两个按钮之后,还可以用自定义的icon 替换默认的。 例如源代码使用 Visual Studio 2010附带的图像库中的图标。 此时,双击 Acquire From Scanner 按钮,这样你将被重定向到代码编辑器。 首先处理 CanExecute 方法钩子以便检查客户端是否桌面上运行,然后处理 Execute 方法钩子以运行扫描仪的( 查看代码中的注释):

PrivateSub AcquireFromScanner_CanExecute(ByRef result AsBoolean)
 ' Write your code here. result = AutomationFactory.IsAvailableEndSubPrivateSub AcquireFromScanner_Execute()
 Dim scanService AsNew DelSole.PhotoService.ScannerService
 'When the scanner service fires the event, the Picture property'of the current photo is assigned with the AcquiredImage property'of the scanner classAddHandler scanService.AcquisitionCompleted, Sub()
 Me.PhotoProperty.Picture = scanService.AcquiredImageEndSubTry Dispatchers.Main.Invoke(Sub()
 Try'Invokes the Scan methodDim imageName AsString = scanService.Scan()
 'This code is executed after the AcquisitionComplete'event is intercepted and asks if the user wants to'delete the scanned image file and just keep the in-memory picDim wantToErase As MessageBoxResult = _
 ShowMessageBox("Do you want to delete the _
 scanned image file from disk?", "", MessageBoxOption.OkCancel)
 SelectCase wantToErase
 CaseIs = Windows.MessageBoxResult.OK
 IO.File.Delete(imageName)
 CaseElseExitSelectEndSelect'This error is thrown if no scanner is turned onCatch ex As System.Runtime.InteropServices.COMException
 If ex.ErrorCode = -2145320939 Then ShowMessageBox("Ensure that your scanner _
 is plugged-in and turned on.")
 Else ShowMessageBox(ex.Message)
 EndIfCatch ex As Exception
 ShowMessageBox(ex.Message)
 EndTryEndSub)
 Catch ex As Exception
 ShowMessageBox("The following error occurred:" & _
 Environment.NewLine & ex.Message)
 EndTryEndSub

因为它将使用适当的线程,并且将避免无效的交叉线程调用,所以你必须从 Dispatcher 运行捕获代码。 接下来的代码处理方法是将 Execute 方法钩子 Acquire From Webcam 按钮:

PrivateSub AcquireFromWebcam_Execute()
 ' Write your code here.'Retrieves the instance of the custom controlDim control = Me.FindControl("ScreenContent")
 'If not visible (default)IfNot control.IsVisible Then'Make it visible control.IsVisible = True'When available...AddHandler control.ControlAvailable, _
 Sub(sender AsObject, e As ControlAvailableEventArgs)
 'Get the instance of the button and change its textDim currentButton = Me.FindControl("AcquireFromWebCam")
 currentButton.DisplayName = "Hide WebCam"'Get the instance of the WebcamControlDim webcamControl = CType(e.Control, DelSole.PhotoService.WebcamControl)
 'When the CaptureCompleted event is fired,AddHandler webcamControl.CaptureCompleted, Sub()
 'The Picture property is assigned with the CapturedImage propertyMe.PhotoProperty.Picture = webcamControl.CapturedImage
 EndSubEndSubElse'If already visible, restore it control.IsVisible = FalseDim currentButton = Me.FindControl("AcquireFromWebCam")
 currentButton.DisplayName = "Acquire From WebCam" 
 EndIfEndSub

代码中的注释应该足够理解,只是注意如何根据控制( 可见或者隐藏)的状态在运行时更改控件( 如 DisplayName ) 上的属性。

测试应用程序

你最后可以按F5来测试应用程序。 打开数据输入屏幕时,你将可以同时启动扫描仪捕获对话框和摄像头控件。 后面的图中显示了后者:

LSPhotoMan10.jpg

你首先需要选择一个可用的设备,然后单击 Start"。 准备好后,单击 get Picture。 此时,运行库将向用户界面发送通知,而 Image Editor 控件将自动显示该图片。 完成后,请不要忘记单击停止。 还可以看看屏幕命令栏上的按钮,它根据控制状态更改它的文本。 下图显示了可以编辑网格屏幕,你可以在它的中查看和编辑集合中可以用图片的列表:

LSPhotoMan11.jpg

Points of Interest

Visual Studio 允许通过扩展性和 Silverlight 4向业务应用程序添加惊人数量的特性。 本文指出了从设备获取图片的容易性,以便你可以使用文档。图片或者产品表示来更好地实现。

历史记录

  • 26th 2011年10月: 初始帖子

WEB  图像  Light  SCA  images  Visual Studio  
相关文章