How to: Call Silverlight Client APIs

本文介绍了Silverlight编程的基础知识,包括Silverlight支持的编程模型、常用API介绍、对象树导航、属性设置方法等内容,并探讨了TextBlock类的使用及鼠标位置获取等实用技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Introduction

important

This topic applies to Silverlight version 1.1. It has not been updated for Silverlight version 2.

The Microsoft Silverlight plugin supports an extensive programming model that includes both managed and unmanaged code. The unmanaged APIs are available in the Silverlight 1.0 release but also exist in the Silverlight 1.1 Alpha release. You can call the managed APIs using any CLR language that has target support in Microsoft Visual Studio 2008 Beta 2. Currently, C# and Visual Basic are supported. You can also use the dynamic language runtime (DLR). For more information about DLR, see Programming Silverlight with Dynamic Languages.

A detailed reference for the Siverlight managed API is not yet available. However, you can use reflection-based tools on the managed assemblies to see what APIs are available. For instructions, see How to: Explore Silverlight Assemblies with the Visual Studio Object Browser.

This topic highlights some of the most common managed APIs that you will use when programming Silverlight-based applications with managed code. In many cases, the managed API is closely related in syntax and its position in the object model to equivalent unmanaged API. Therefore, you might be able to use some of the unmanaged reference as the basis for managed programming tasks. However, sometimes the equivalents are not obvious because of a different object model position or a changed name.

The Silverlight Managed Class Hierarchy

Many of the managed classes that support programming against the Silverlight control and the UI features specifically share the following initial hierarchy:

DependencyObject

  • UIElement

    • FrameworkElement

If you have programmed with the Windows Presentation Foundation (WPF), this hierarchy will look very familiar. However, unlike using WPF, when programming with Silverlight you can generalize the role of each class in this hierarchy. In Silverlight you can generally think of the FrameworkElement class as being the common "element" class that contains APIs that are useful for elements that are defined in XAML and are part of your UI.

That does not mean everything that you instantiate in XAML is a FrameworkElement. There are many other types of elements where the purpose of the element is to fill values of certain UI-defining elements, but where the property can be declared in an elaborate markup. The canonical examples are derived classes of Animation, or Storyboard, none of which are FrameworkElement objects. Rather, animations and Storyboard are used to target properties of UI elements.

Walking the Object Tree and Finding Named Objects

The object tree of an individual XAML page always starts with the XAML root element. The existence of the object tree assumes that the XAML page is assigned as the source of a Silverlight control and has therefore been parsed. (It is also possible to create XAML files as resources, or subsequently loaded them into or attach them to the object tree, in which case the object tree becomes attached to the root where the XAML is attached.)

In managed code, when you have an x:Class defined for the XAML root, it is simple to get a reference to the XAML root: you can just call the language keywords "this" or "Me". However, not all properties of "this" that deal with the extension of the object tree around the object are necessarily available from contexts such as the class constructor. As of the constructor call, much of the overall application object tree does not exist yet; that must wait until the XAML is parsed, although there are ways around this issue.

For other objects in the tree beyond the root, you have three alternatives, two of which are related.

  • You can walk the tree downwards starting from the root, using the relevant content model properties, for instance Panel.Children, or generic collection indexers. This is probably the least preferable alternative, because it requires intimate knowledge of the markup or the code construction of the object tree. It is usually possible to walk into content models or collections somehow, but there is no single API for doing so. Generally, you might use this technique only to walk single levels into content models or collections.

  • You can assign an x:Name to a XAML element. Then you obtain a reference to the named object by calling the API DependencyObject.FindName. (DependencyObject is low in the heirarchy, so you will find this API on most elements.) If you have programmed the unmanaged APIs for Microsoft Silverlight 1.0, this technique will be familiar to you. FindName returns type Object, so one slight disadvantage of FindName is that you must cast the returned object in order to do something useful with it. That means that you must try to cast the object to an acceptable type you plan to work against or cast it to its reported type.

  • As long as you are using Microsoft Visual Studio 2008 Beta 2 and the associated Silverlight templates and build actions, there is a better alternative. Give your elements an x:Name as described previously. However, instead of using FindName, consider the x:Name to be equivalent to a field-style object reference to the constructed class. For example, if you create an element <TextBlock x:Name="myTextBlock"/>, and you are programming in the x:Class, merely type myTextBlock to get the reference, then a dot, and call the relevant property or method, or attach events. You can see each of the members available immediately through IntelliSense. These automatic references from the XAML are made possible through generated code that processes the XAML every time it is loaded. The generated code stores references in a generated partial class that combines with your partial x:Class. You can see the mechanisms for this in your managed Silverlight project: the partial class definition for x:Class, the pre-wired Loaded handler on the XAML root that calls InitializeComponent, and the generated file in the obj directory (which redefines InitializeComponent to create the references on each load). You may find that when you add a new named element to the XAML, you will sometimes need to compile to "prime" the code generation so that IntelliSense can obtain any newly created name references in the markup.

  • The generated code and its references are nice to have, but keep in mind that you do not always have them available. For instance, when you do Silverlight control composition, the relationship between the XAML and the code is somewhat reversed, and the XAML is conceptually more in a late-binding position versus the control class. Therefore, you might find yourself using FindName more often for custom control code than you do for application page code.

To walk the object tree towards the root element, you can use the API FrameworkElement.Parent. When you reach the root, FrameworkElement.Parent will return null.

Getting or Setting Attached Properties

An attached property is a XAML language concept whereby elements can be assigned attributes for a property, even though that property is not present in the members list of the code type that backs the element. The primary examples of attached properties in the Silverlight client API are the three Canvas properties that enable child elements of a Canvas to specify their layout. These are Canvas.Left, Canvas.Top, and Canvas.ZIndex. When you set these properties in XAML attribute syntax, you must qualify them with the Canvas owner type in an Owner.Property form, and you do not set the attributes on Canvas. Instead, you set the attributes on immediate child elements of a Canvas, and the parent Canvas reads these properties in its internal implementation to make layout decisions about its child elements.

Because of the nature of attached properties, getting or setting them in managed code is not done in Object.Property form, because there are always two objects in play (the property owner as far as XAML parsing is concerned, and the object instance where the property is set).

In managed code, you get the value of an attached property by calling DependencyObject.GetValue. The parameter you pass to this method is a property identifier, which is a field member of the class that "owns" the attached property definition. You set the value using DependencyObject.SetValue. The first parameter is again the property identifier, and the second parameter is the value to set. In each case, the method is an instance usage, called against the instance where the attached property value is stored.

GetValue and SetValue potentially have a wider usage. You can use them to get or set any Silverlight client property that has a property identifier. For instance, you could call myTextBlock.SetValue(TextBlock.TextProperty "hello"). But in practice this is almost never done for "regular" (nonattached) properties, because the Instance.Property form for setting and getting properties is much more intuitive.

Height and Width

Height and Width exist on FrameworkElement. You can set Height and Width on derived classes such as Canvas, TextBlock and the various Shape derived classes.

A small number of elements (such as TextBlock) also have an ActualWidth and ActualHeight property. These are calculated, read-only properties. ActualWidth and ActualHeight help you with layout for objects where the rendered size is influenced by multiple properties. For instance, when the layout involves text in a TextBlock, the size of the text is influenced by the FontSize, FontFamily, FontSpacing, and, of course, the Text.

note

Height and Width for custom controls might currently require a workaround, depending on how you use the base properties. For details, see Creating Custom Controls for Silverlight.

TextBlock and Text APIs

The TextBlock class includes a number of APIs. There is a very limited text object model (exposed through the Inlines collection), and there are several expected text-related properties for text in UI:

  • FontFamily: Set as a string that names the font family. Silverlight initially supports only a few fonts (see the unmanaged documentation for TextBlock for details). You can download fonts other than the initial fonts by calling TextBlock.SetFontSource.

  • FontSize: Set in pixels.

  • FontStretch: Uses the FontStretches enumeration. Check the enumeration values in the object browser, or see the Silverlight 1.0 documentation for details.

  • FontStyle: A value of the FontStyles enumeration (Normal, or Italic).

  • FontWeight: Uses the FontWeights enumeration. Check the enumeration values in the object browser, or see the unmanaged Silverlight documentation for more details.

  • Foreground: Typically, a solid color declared by XAML attribute, but it can also be set to any class derived from Brush (for example, an ImageBrush or GradientBrush) for special effects.

  • TextDecorations: A value of the TextDecorations enumeration (None, or Underline).

  • TextWrapping: A value of the TextWrapping enumeration (NoWrap, or Wrap).

  • Text

Colors and Brushes

When set in XAML as an attribute value, you can specify solid colors with approximately 256 named color values based on UNIX X11, including intriguing colors such as "MistyRose" and "PapayaWhip". Or, you can specify RGB or ARGB values by preceding the string value with a hash sign (#). In the Silverlight managed API, the number of predefined colors available is smaller; it is limited to 16 colors. Therefore, the primary mechanism for defining a solid color is to call the static Color.FromArgb, Color.FromScRgb, or Color.FromRgb method. Also, the various classes derived from Brush (such as SolidColorBrush) have only the default constructor. They do not have any convenience constructors. You must therefore set the relevant properties for that Brush type individually after construction. For classes such as RadialGradientBrush you must also construct each GradientStop and add that stop to the GradientCollection.

A large amount of routine code can be required, especially to produce brushes and to handle the potential for reusing a brush. The following development strategy will be helpful when a brush gets significantly complex:

  1. Define the brush as a XAML file, or even as a string in valid XAML form (including the xmlns at the root).

  2. Include that string or file as an embedded resource for your application.

  3. Access the resource as a stream, and use the stream as a string source for the XamlReader.Load API (more about this API in an upcoming section).

  4. Cast the result to the appropriate Brush class, and use it to set your property.

One advantage of this approach is that you can use design tools such as Microsoft Expression Blend to produce the XAML, which will yield satisfying results more quickly than iterating on ARGB values in code or pasting strings from other design tools. The Silverlight managed APIs do not yet have a resources system that is quite as developed as the ResourceDictionary-based resources system for WPF, but embedded resources can serve the purpose.

Mouse and Mouse Position

Browser client APIs can be used to get mouse positions in the overall browser, but that is usually not adequate for Silverlight-based applications. Instead of using a service that constantly monitors the mouse input device (which is the case for WPF) the mouse position is reported only in response to mouse events. However, one of these events is MouseMove, which fires frequently. Even if the mouse never moves, you can get an initial mouse position when the MouseEnter event for the main Canvas fires as the Canvas is loaded (so long as the mouse started over the client area). You obtain the mouse pointer position by calling the method MouseEventArgs.GetPosition from the event data instance, instead of using directly-defined X and Y properties. This method takes a parameter of type UIElement; the element you provide to the method will be used to calculate a position offset. If you pass null, the coordinate system is relative to the Silverlight control content area. Otherwise, the typical element to pass to the GetPosition input parameter if you do not pass null is the event sender (which you will need to cast to UIElement). You can pass any element, including elements not clicked upon by strict hit-testing definition, which might mean that the X and Y values you get from GetPosition are negative.

The two most common scenarios for getting the mouse position are to determine where the mouse was when a button was clicked, and to determine where the mouse is when crossing a boundary. Both of these scenarios are involved in a drag-and-drop scenario as well.

This mouse event and position determination behavior is appropximately the same for either managed or unmanaged Silverlight-based applications, but it is quite different from WPF and therefore is worth calling out.

XamlReader

In JavaScript, there are no constructors, so you cannot create a new instance of an element you want to add to a tree. You can use DHTML-like strategies such as having parallel trees that are already constructed and using a hide-show approach, you can use animations (but only to change properties, not add to the tree), or you need to call Control.content.createFromXAML to effectively use the parser as a constructor engine. For this reason, you might have called createFromXAML fairly frequently in Silverlight 1.0 if you were creating a particularly dynamic UI.

In managed code, you have access to constructors. Therefore, in many cases, calling XamlReader.Load (which is the managed createFromXaml equivalent) is unnecessary, particularly because you are already working in a code model and calling a constructor is not difficult. The constructor approach, combined with setting properties on the newly constructed instances and adding them to the existing object tree, works well if the run-time design changes are simple.

On the other hand, if the design changes were complex, and you had a designer-coder responsibility split where the designer produced two different UIs for each state, it might make sense to load from XAML to refresh the UI. However, in this case, you really should not load XAML from a string directly, as the XamlReader.Load signature might indicate. Instead, it is better code style to obtain the string from a stored resource or a separate file, perhaps using System.IO.StreamReader, so that the XAML handoff from designer to coder will consist of a file rather than strings.

For both the JavaScript createFromXAML and XamlReader.Load methods, you should also consider that APIs that take markup as strings can actively fight the UI-designing capabilities of whatever design tool is used to define the UI markup, if you use those APIs indiscriminately.

Downloader

In managed code, you can create the Downloader object directly using its constructor (in unmanaged code, you had to call Control.createObject to get it from the Silverlight control).

After you construct Downloader, you typically attach handlers to one or more of the DownloadProgress, DownloadFailed, or Completed events. After that, you call Open, passing the Uniform Resource Identifier (URI) of the content to download. Finally, you call Send to initiate the request.

As with Silverlight 1.0 and the unmanaged API, the managed Downloader has certain security restrictions. You cannot request content across domains, and you cannot use the file:\\ scheme in a download URI.

Getting Events and Information from the Hosting Browser

You can access the HTML DOM for the document contained in the browser, and get quite a bit of information that way (see Accessing the HTML DOM from Managed Code). However, there is one particular set of information that is difficult to obtain that way: the size of the hosting browser window (minus toolbars, edges and chrome), and when the user changes that size. A quick way to get that information is to handle the events of the BrowserHost class, which exists in the System.Windows.Interop namespace. At any time, you can check the values of the BrowserHost.ActualWidth and BrowserHost.ActualHeight properties. You can also write handlers for the Resize or FullScreenChange event so that you know specifically when the ActualWidth or ActualHeight changes, and which user action (resize or toggle fullscreen) caused the change.

Rectangle and Rect

Silverlight has two similarly named types: the Rectangle class, which is in the namespace System.Windows.Shapes, and the Rect structure, which is in System.Windows. The Rectangle class is a UI element that you can place on a page to fill an area with a particular color or brush. The Rect structure is not a UI element; it is a structure that is used as a value for other types of objects that are generally rectangular, and it may or may not have an immediate visual representation. For example, Rect describes a RectangleGeometry or the bounds of an ink Stroke. Rect includes several utility methods so that you can compare Rect instances, or adjust values of an existing Rect.

转载于:https://www.cnblogs.com/Reaper1129/archive/2008/04/14/1153505.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值