zoukankan      html  css  js  c++  java
  • WPF,Silverlight与XAML读书笔记第四十七

    说明:本系列基本上是《WPF揭秘》的读书笔记。在结构安排与文章内容上参照《WPF揭秘》的编排,对内容进行了总结并加入一些个人理解。

    这部分内容主要介绍Silverlight与浏览器的交互,包括使用JavaScript来控制Silverlight。这其中起主要作用的是Silverlight插件与Silverlight.js这个文件。

    首先我们要展示怎样在浏览器中嵌入Silverlight对象,有两种方式实现这个目的,第一种是使用JavaScript加载Silverlight控件,这涉及到上文提到的一个很重要的文件 – Silverlight.js,其在Silverlight插件与Silverlight内容之间建立起桥梁。

    Silverlight文件包含两个初始化Silverlight控件的方法createObject和createObjectEx。它们的区别在于createObjectEx将参数序列化为JSON。

    在页面引用了Silverlight.js后,我们就开始调用createObject方法初始化Silverlight。在这之前我们先了解一下createObject方法的参数。

    • Source: 用来设置控件要显示的XAML代码或XAP应用程序,其有如下几种设置方式:
    • parentElement: 网页中用于包含Silverlight控件的div的id
    • ID: Silverlight控件的唯一标识
    • 这个属性是一个属性数组,其中包含如下这些属性
      • Silverlight控件的宽度,接受像素值或百分比
      • height: Silverlight控件的高度,接受像素值或百分比
      • backgroud: 控件的背景颜色,接受ARGB或颜色名
      • framerate: 动画的最大帧率,默认值24
      • isWindowless: 布尔值,设置HTML内容是否可以显示到Silverlight上面,默认值为false。
      • enableHtmlAccess: 设置Silverlight的内容是否可以访问浏览器的DOM模型,默认值为true。
      • inplaceInstallPrompt:布尔值设置Silverlight的安装模式,true表示直接安装,false为间接安装
        • 直接安装:用户无需离开访问的页面,只需接受一个软件许可协议,控件就会被自动下载安装。
        • 间接安装:用户被导航到微软网站,在特定的页面中接受协议,下载并安装控件。
        • version: Silverlight控件向前兼容的最低版本
    • 这个参数是一个事件数组
      • onLoad: 控件加载完毕后触发的事件
      • onError: 遇到异常时触发的事件
      • onFullScreenChange: Silverlight中指示全屏状态的FullScreen改变时触发
      • onResize: 当Silverlight的ActualWidth或ActualHeight改变时触发
    • initParams:定义加载控件时,传入的用户自定义参数的集合,该参数为字符串类型。这样我们可以把所要传递的参数使用逗号分隔,组成一个字符串传递过去。在接收并使用参数时,可以通过Js的split方法将字符串转化为一个数组以使用。参数的处理一般位于onLoad事件的处理程序,后文有详细介绍。
    • userContext: 该参数用于为控件设置一个唯一标识。这个标识主要用于传递给onLoad事件处理函数用以区分同一页面中不同的Silverlight控件。这个参数的行为与initParams相同,所以也可以用它来传递参数,虽然这不是推荐做法。具体使用可见下文代码。

       

    上面介绍了这么多,下面我们通过一段代码演示createObject方法的使用:

     1 Silverlight.createObject(
     2     "Page.xaml",
     3     document.getElementById("SilverlightControlHost"),
     4     "mySilverlightControl",
     5     {
     6          '300',
     7         height: '300',
     8         inplaceInstallPrompt: false,
     9         background: '#D6D6D6',
    10         isWindowless: 'false',
    11         framerate: '24',
    12         version: '2.0'
    13     },
    14     {
    15         onError:null,
    16         onLoad:null
    17     },
    18     "p1,p2,p3",
    19     null
    20 );

    上面代码中指定的XAML源 – Page.xaml很简单,如下所示:

     1 <UserControl x:Class="SilverlightApplication3.MainPage"
     2     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     3     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     4     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
     5     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
     6     mc:Ignorable="d"
     7     d:DesignHeight="300" d:DesignWidth="400">
     8     <Grid x:Name="LayoutRoot" Background="White">
     9         <TextBlock Text="Hello, World!"></TextBlock>
    10     </Grid>
    11 </UserControl>

    这样一个最简单的可运行的Silverlight例子就完成了。

    下面是实现同样效果的另一种途径 – 使用Object标签。通过<object>标签可以不使用js,直接在页面中以声明方式加载Silverlight控件,同样类似于其它插件的加载,可以使用<param>来设置参数。

        使用<object>的一个好处在于,可以在<object>之前放置一段HTML,从而在Silverlight没有正确初始化时在其位置显示这段HTML。如这种情况,在客户端没有Silverlight插件,或版本过低时可以通过这段HTML提供一个下载安装的链接。这种方式可以参考如下的例子:

     1 <object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="100%">
     2     <param name="source" value="ClientBin/SilverlightApplication3.xap"/>
     3     <param name="onError" value="onSilverlightError" />
     4     <param name="background" value="white" />
     5     <param name="minRuntimeVersion" value="4.0.50826.0" />
     6     <param name="autoUpgrade" value="true" />
     7     <a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=4.0.50826.0" style="text-decoration:none">
     8          <img src="http://go.microsoft.com/fwlink/?LinkId=161376" alt="获取¨Microsoft Silverlight" style="border-style:none"/>
     9     </a>
    10 </object>

    注意:<object>标签中data属性的值:"application/x-silverlight-2",这是Silverlight的MINE类型。Silverlight插件在加载Silverlight内容时会检查该值,如果是一个不支持的MINE类型,则无法正确加载(这是那段HTML代码就起作用了:))

        使用这种方式加载Silverlight控件的另一个好处在于可以在不接受js内容的地方,如第三方博客服务中,加载Silverlight内容。

    说完了两种加载Silverlight内容的方式。接下来介绍处理控件加载事件。

    我们可以定义一个函数来响应控件的onLoad事件。这个函数应符合如下格式的声明:

    Function handleLoad(control, userCotext, rootElement);

    这三个参数分别为:

    • 控件的引用,我们前文介绍的createObject的initParams函数传递的值就存储于control.initParams属性中。
    • 上下文信息,这是createObject方法userContext方法传递的参数。
    • XAML根元素的引用

    注意:Silverlight中加载顺序

    XAML UI元素中定义的任何loaded事件会在Silverlight控件的onLoad事件之前触发。Silverlight有一个布尔类型的只读属性 – IsLoaded。该属性默认值为false,它在Silverlight控件的onLoad事件发生前被设置,通过它可以判断控件是否加载完成。

    下面的示例代码,我们分别演示了处理initParams参数,接收userContext。

    1 function handleLoad(control, userContext, rootElement) {
    2     //接收并处理自定义参数
    3     var params = control.initParams.Split(",");
    4     for (var i = 0; i < params.Length; i++) {
    5         alert(params[i]);
    6     }
    7     //接收userContext
    8     alert(userContext);
    9 }

    处理异常

        当Silverlight遇到错误,如XAML解析器无法完成解析,加载未正确完成时,在createObject()创建Silverlight控件时定义的onError事件处理程序就会被调用。

        如果onError参数没有被设置,或设置为null,则默认的错误处理函数会被调用并以alert()的方式给出错误信息。

        自定义的onError事件处理函数,我们称其为handleError,接收两个参数 – sender – 表示引发错误的对象,errorArguments - 为错误事件参数。errorArguments为ErrorEventArgs类型,其中有一个errorType属性表明具体的错误类型,可能的值为RuntimeError或ParserError。这两个类型都是ErrorEventArgs的子类,当通过errorType确定具体错误类型后,就可以把errorArgments作为具体子类的对象对待并访问其中特定的属性。

    ParserErrorArgs中的一些属性:

    • charposition属性,包含了出错字符串的位置信息。
    • linenumber属性,包含出错的行号信息
    • xamlFile,包含出错文件的信息
    • xmlAttribute包含出错的xml属性信息
    • xmlElement包含出错元素的信息

    RuntimeErrorEventArgs包含的属性:

    • charPosition属性,包含了出错字符串的位置信息。
    • lineNumber属性,包含出错的行号信息
    • methodName包含出错方法的信息

    最后我们来看一段handleError函数的代码:

     1 //假定这里遇到一个分析器错误
     2 //如前文所述,当我们无法预先知道错误类型时,需要查询errorType属性
     3 function handleError(sender, errorArguments) {
     4     var strError = "Error Details: 
    ";
     5     strError += "Type: " + errorArguments.errorType + "
    ";
     6     strError += "Message: " + errorArguments.errorMessage + "
    ";
     7     strError += "Code: " + errorArguments.errorCode + "
    ";
     8     strError += "Xaml File: " + errorArguments.xamlFile + "
    ";
     9     strError += "Xaml Element: " + errorArguments.xmlElement + "
    ";
    10     strError += "Xaml Attribute: " + errorArguments.xmlAttribute + "
    ";
    11     strError += "Line: " + errorArguments.lineNumber + "
    ";
    12     strError += "Position: " + errorArguments.charPosition + "
    ";
    13     alert(strError);
    14 }

    这个自定义的错误处理函数中,使用自定义的方式展示了Silverlight中发生的错误。

    Silverlight控件的属性

    接下来这一部分我们介绍Silverlight插件所支持的属性,方法与事件模型。另外也介绍Silverlight控件对载入与错误事件的处理,包括Silverlight提供的默认的错误处理函数以及如何重写这个函数,如何传递自定义参数和上下文信息给Silverlight控件。

        控件的属性主要分三类:直接访问类,内容访问类,设置访问类

        直接访问类的属性可以使用"Control.Propertyname"的语法直接访问。内容访问类与设置访问类分别使用"control.content.propertyname"与"control.settings.propertyname"的语法访问。

    直接访问类属性

    • initParams:前文有介绍,只能在初始化Silverlight控件时设置。
    • isLoaded:只读布尔属性,表明控件是否加载完
    • source:指定要显示的XAML内容源。其设置方式在介绍createObject()方法参数部分有详细介绍

    内容访问类

    • actualHeight:返回Silverlight控件区域的高度,以像素为单位。

      这个属性的值有几种可能,当初始化时使用绝对值(像素)设置,这个属性的值就与设置值相同,如果初始化时使用百分比设置,这个属性会随着浏览器窗口的改变而改变,当控件在全屏模式下时,它的值与系统桌面的高度相同。

    • actualWidth:返回控件实际显示宽度,决定这个属性的因素与actualHeight相同。
    • fullScreen:控制Silverlight控件是标准模式还是全屏模式。默认值false即标准模式

    设置访问类

    • background: 设置Silverlight控件的背景颜色,其接受多种格式,包括颜色名,有或没有alpha值的8位或16位RGB格式。
    • enableFrameRateContent: 是否在浏览器状态栏中显示Silverlight当前的帧率,默认值为false。
    • enableHtmlAccess: 是否允许XAML内容访问浏览器DOM对象默认值为true。
    • enableRedrawRegious: 是否让Silverlight控件在每一帧重画每个区域。默认值为false,当设置为true时有利于提高程序性能。
    • maxFrameRate: 设置Silverlight动画的最大帧率,默认值为24,可设最大值为64。
    • version: 当前Silverlight插件的版本号。这是一个由逗号分隔的四个数字组成的字符串,四个数字分别表示主版本,次版本,编译号和修订号,其中前两个号是必须的。
    • windowsless: 该属性被设置为true时,控件为非窗口模式,Silverlight的内容可以高效率的显示在HTML内容的下面。

    Silverlight控件的方法

        Silverlight控件拥有一个直接访问类方法和三种内容访问类方法。直接访问方法为createObject,其用来创建实现特定功能的可清除对象。在Silverlight中这样的对象只有Downloader对象(后文会详细这个对象),下面介绍的3个方法是内容访问方法,应使用control.content.methodName()来调用。

    • createFromXmal方法

      该方法将定义好的XAML内容动态地加入Silverlight控件中。该方法接收两个参数,第一个是包含要添加XAML内容的字符串,第二个参数指示是否创建命名空间,当为true时,会在引入的XAML中添加一个有唯一值的x:Name属性以与现有XAML元素名称区分。

      添加的内容有一个限制,即只能有一个根节点,否则该把这些元素套在一个<Canvas>标签内。

      另外CreateFromXaml创建的对象并没有立刻被添加到Silverlight控件中,CreateFromXaml方法返回一个节点的引用,需要手动把该节点的引用加入控件树中。下面的代码给出示例:

      1 function handleLoad(control, userContext, sender) {
      2     var xmalFragment = '<TextBlock Canvas.Top="60" Text="This is Inserted." />';
      3     var textBlock = control.content.createFromXaml(xmalFragment);
      4     sender.children.add(textBlock);
      5 }
    • CreateFromXamlDownloader方法

      这个方法结合下文介绍的Downloader对象一起使用。该方法接收两个参数,第一个是用于下载XAML代码的Downloader对象,第二个参数用于指定使用Downloader对象包的哪一部分,如下载的是一个压缩包,该属性就设置为压缩包中XAML代码的文件名,如果下载的不是压缩包,该参数传入空字符串即可。

    • fullName方法

      使用该方法通过x:Name查找指定的节点,如果找到则返回该节点的引用,否则返回null。

    Downloader对象

    接下来,介绍Silverlight中的Downloader对象,包括如何使用Downloader对象动态的向Silverlight程序中添加内容。Downloader对象用于异步下载额外内容,如包括单个资源的文件或多个资源的压缩包。Downloader对象通过JavaScript访问网络资源,Downloader对象只能从Silverlight程序所在的站点上下载内容,如果试图从别的站点上下载文件会抛出异常。

    Downloader对象的属性

    • downloadProgress: 该属性为0到1间的值,代表当前下载进度,1表示下载完毕。
    • status: 该属性提供当前下载进程的HTTP状态值,这是一个标准的HTTP状态。如404表示文件未找到,200表示成功。
    • statusText: 该属性表示当前下载状态的文本信息,它与status属性保持一致,对于成功完成的HTTP请求,status值为"200",StatusText值为"OK"。更多状态码与对应文本可参见W3C对于HTTP协议的描述。
    • uri: 要下载的目标对象的地址

    Downloader对象的方法

    • abort: 该方法用于取消当前下载,并将所有属性设为默认值。
    • getResponseText: 该方法返回下载内容字符串形式的结果,该方法有一个可选参数,用来指定需要返回其内容的压缩包中的文件的文件名。
    • open: 该方法用于初始化下载,其接受两个参数,第一个是下载的请求方式,目前Silverlight只支持GET方式请求。
    • send: 在使用Open方法初始化过的Downloader对象上调用该方法来执行下载请求。

    Downloader对象的事件

    • completed: 下载完毕时触发该事件。此事件的处理函数接收两个参数。第一个是事件触发者,此处即Downloader对象,第二个是传入事件处理函数的一组参数。
    • downloadProgressChanged: 在内容下载过程中触发该事件。如当下载进程达到5%时会触发该事件,当进程达到100%时,在触发此事件的同时会触发completed事件。

    下面我们通过代码来看一下Downloader对象的使用方法:

    1 function handleLoad(control, userContext, sender) {
    2     var downloader = control.createObject("downloader");
    3     downloader.addEventListener("downloadProgressChanged", "handleDLProgress");
    4     downloader.addEventListener("completed", "handleDLComplete");
    5     downloader.open("GET", "z.png");
    6     downloader.send();
    7 }

    下面的代码是两个事件处理函数的实现,分别用来反馈下载进度与通知下载完成。

     1 function handleDLProgress(sender, args) {
     2     var ctrl = sender.getHost();
     3 
     4     var t1 = ctrl.content.findName("label");
     5     var v = sender.downloadProgress * 100;
     6     t1.Text = v + "%";
     7 }
     8 
     9 function handleDLComplete(sender, args) {
    10     alert("Download complete");
    11 }

    通过JavaScript操作Silverlight界面元素

    最后我们来看一下Silverlight界面元素的编程模型,其中包括如何使用JavaScript来使用这些界面元素暴露的方法与事件。

    Silverlight界面元素包括Canvas,Image,MediaElement及各类Shape,Path等,它们都为JavaScript的访问暴露了一些方法。下面逐一介绍这些方法:

    • AddEventListener/RemoveEventListener方法:

      AddEventListener方法主要用于给界面元素添加一个事件侦听器,而相反RemoveEventListener用来删除一个界面元素与事件的关联。后着通过前者返回的整数值或事件处理程序的名称来完成删除。
      下面的代码展示了AddEventListener事件的订阅与事件处理函数的实现:

    1 function handleLoad(control, userContext, sender) {
    2     sender.addEventListener("mouseLeftButtonDown", handleMouse);
    3 }
    4 function handleMouse(sender, mouseEventArgs) {
    5     alert(mouseEventArgs.getPosition(null).x + ":" + mouseEventArgs.getPosition(null).y);
    6 }
    • findName方法

      此方法通过搜索XAML树查找指定的对象。如果找到会返回该对象的引用;反之返回空(null),同样下面给出一个示例:

    XAML:

    1 <Grid x:Name="LayoutRoot" Background="White">
    2     <TextBlock x:Name="tb1" Text="Hello, World!"></TextBlock>
    3     <TextBlock x:Name="tb2" Text="Hello, World 2!"></TextBlock>
    4     <TextBlock x:Name="tb3" Text="Hello, World 3!"></TextBlock>
    5 </Grid>
     

    JavaScript:

    1 function handleLoad(control, userContext, sender) {
    2     var tb1 = sender.findName("tb1");
    3     tb1.Text = "Hello World Updated";
    4 }
    • GetHost方法

      在界面元素上调用这个方法,可以得到包含这些界面元素的Silverlight控件的引用,这样可以获得Silverlight控件的版本号。

    • getParent方法

      通过findName方法成功得到一个界面元素的引用后,可以调用在这个界面元素上调用getParent方法来返回其父元素的引用,同样如果找不到会返回null。

    • getValue/setValue方法

      这两个方法用于访问与设置Silverlight中的附加属性。通过下面的例子可以对这两个方法的使用一目了然:

      1 var tb1 = sender.findName("tb1");
      2 tb1.setValue("Canvas.Top", 20);

      提示:

      也可以通过"[]"这样索引的形式访问或修改附加属性的值,如上面的代码等价于下面的代码: tb1["Canvas.Top"] = 20; 

    • setFontSource方法

      这个方法是TextBlock独有的,通过这个方法可以给TextBlock应用新字体。如可以使用Downloader对象下载你想要设置的字体,在下载成功完成后将Downloader对象传递给TextBlock的SetFontSource方法,这样就可以将新字体应用到TextBlock。另外注意,你需要有分发这种字体的权利。下面的代码完整的展示了上文所述的场景:

       1 function handleIt(sender, eventArgs) {
       2     var control = sender.getHost();
       3 
       4     var downloader = control.createObject("downloader");
       5     downloader.addEventListener("Completed", "onCompleted");
       6     downloader.open("GET", "NewFont.TTF");
       7     downloader.send();
       8 }
       9 
      10 function onCompleted(sender, evnetArgs) {
      11     var myTextBlock = sender.findName("myTextBlock");
      12     myTextBlock.setFontSource(sender);
      13     myTextBlock.fontFamily = "Simhei";
      14 }

    界面元素也支持许多事件,可以通过前文介绍的JavaScript中的AddEventListener方法订阅这些事件,也可以直接在XAML中添加这些事件的处理方法(这是更常见的做法),下面依次介绍这些事件:

    • GotFocus:当界面元素得到鼠标焦点的时候触发。
    • LostFocus:该事件与GotFocus事件相反,在对象失去焦点时触发。
    • keyDown:该事件在界面元素拥有焦点,并在按下键盘键时触发,该事件包含两个参数,第一个是事件发送者的引用,第二个是KeyEventArgs对象,这个对象包含多个属性:
      • key: 一个整数,代表哪一个键被按下,具体值定义于Silverlight SDK中。
      • platfromKeyCode:这个值是由操作系统决定的
      • shift:布尔型,表示shift键是否被按下
      • ctrl:布尔型,表示Ctrl是否被按下
    • keyUp:该事件在某个对象拥有焦点并释放按键的时候触发,此事件与KeyDown事件拥有相同的参数。

    注意:KeyDown与KeyUp事件在Silverlight全屏模式下不会触发

     
    • Loaded:该事件在对象被解析并加入到Silverlight控件之后,显示之前触发。
    • MouseEnter:鼠标进入对象的区域时触发。
    • MouseLeave:与MouseEnter相反,在鼠标离开对象区域时触发。
    • MouseleftButtonDown:该事件在当用户在某个对象上按下鼠标左键时触发。
    • MouseLeftButtonUp:该事件在松开鼠标左键的时候触发。
    • MouseMove:该事件在鼠标在界面元素上移动时触发。

    最后我们看一个使用JavaScript操作界面元素的例子 – 实现鼠标拖拽界面元素。

    首先是XAML,其中包含了要拖动的元素,并使用XAML订阅了一些事件:

     1 <Canvas Height="400" Width="400">
     2     <Ellipse Canvas.Top="0" Height="10" Width="10" Fill="Black" 
     3         MouseLeftButtonDown="onMouseDown" 
     4         MouseLeftButtonUp="onMouseUp" 
     5         MouseMove="onMouseMove" />
     6     <Ellipse Canvas.Top="20" Height="10" Width="10" Fill="Black" 
     7         MouseLeftButtonDown="onMouseDown" 
     8         MouseLeftButtonUp="onMouseUp" 
     9         MouseMove="onMouseMove"/>
    10     <Ellipse Canvas.Top="40" Height="10" Width="10" Fill="Black" 
    11         MouseLeftButtonDown="onMouseDown" 
    12         MouseLeftButtonUp="onMouseUp" 
    13         MouseMove="onMouseMove"/>
    14     <Ellipse Canvas.Top="60" Height="10" Width="10" Fill="Black" 
    15         MouseLeftButtonDown="onMouseDown" 
    16         MouseLeftButtonUp="onMouseUp" 
    17         MouseMove="onMouseMove"/>
    18 </Canvas>

    下面是事件处理函数:

     1 var beginX; 
     2 var beginY; 
     3 var isMouseDown = false; 
     4 function onMouseDown(sender, mouseEventArgs) 
     5 { 
     6     beginX = mouseEventArgs.getPosition(null).x; 
     7     beginY = mouseEventArgs.getPosition(null).y; 
     8     isMouseDown = true; 
     9     sender.captureMouse(); 
    10 }
    11 function onMouseMove(sender, mouseEventArgs) 
    12 { 
    13   if (isMouseDown == true) 
    14     { 
    15         var currX = mouseEventArgs.getPosition(null).x; 
    16         var currY = mouseEventArgs.getPosition(null).y; 
    17         sender["Canvas.Left"] += currX - beginX; 
    18         sender["Canvas.Top"] += currY - beginY; 
    19         beginX = currX; 
    20         beginY = currY; 
    21     } 
    22 }
    23 function onMouseUp(sender, mouseEventArgs) 
    24 { 
    25     isMouseDown = false; 
    26     sender.releaseMouseCapture(); 
    27 }

    其中CaptureMouse方法用于在拖动某个对象过程中,让该对象一直拥有鼠标事件,MouseMove的处理函数中通过参数传入的值持续改变被拖动对象的位置。我们还使用isMouseDown变量来保证只处理鼠标按下(即拖动过程中)时触发的MoveMouse事件。

    下面给出用C#实现相同功能的代码,值得注意的是由于Canvas.Left和Canvas.Top属性是依赖属性,无法像JavaScript中那样直接访问,而需要使用Canvas.GetLeft和Canvas.GetTop这样的方法来访问:

     1 private double beginX, beginY;
     2 private bool isMouseDown = false;
     3 
     4 private void mouseInit(object sender, MouseButtonEventArgs e)
     5 {
     6     Ellipse el = sender as Ellipse;
     7     el.CaptureMouse();
     8     beginX = Canvas.GetLeft(el);
     9     beginY = Canvas.GetTop(el);
    10     isMouseDown = true;
    11 }
    12 
    13 private void mouseMove(object sender, MouseEventArgs e)
    14 {
    15     if (isMouseDown)
    16     {
    17         Ellipse el = sender as Ellipse;
    18         var x = e.GetPosition(null).X;
    19         var y = e.GetPosition(null).Y;
    20         Canvas.SetLeft(el, Canvas.GetLeft(el) + x - beginX);
    21         Canvas.SetTop(el, Canvas.GetTop(el) + y - beginY);
    22         beginX = x;
    23         beginY = y;
    24     }
    25 }
    26 
    27 private void mouseRelease(object sender,MouseButtonEventArgs e)
    28 {
    29     Ellipse el = sender as Ellipse;
    30     el.ReleaseMouseCapture();
    31     isMouseDown = false;
    32 }
     

    本文完

  • 相关阅读:
    20200917-2 词频统计
    20200910-2 博客作业
    20200910-1 每周例行报告
    20200910-3命令行和控制台编程
    使用Requests库实现api接口测试(Python)
    Python Lambda函数的几种使用方法
    文本与向量之间的转换
    Oracle连接出现error: ORA-12505, TNS:listener does not currently know of SID given in connect descriptor
    一图看懂新一代人工智能知识体系大全
    SqlDeveloper连接MySQL出现The connection property ‘zeroDateTimeBehavior’ acceptable values are: ‘CONVERT_TO_NULL’, ‘EXCEPTION’ or ‘ROUND’. The value ‘convertToNull’ is not acceptable 错误
  • 原文地址:https://www.cnblogs.com/lsxqw2004/p/4632563.html
Copyright © 2011-2022 走看看