XAML

Properties and Events in XAML

Simple Properties and Type Converters

To bridge the gap between string values and nonstring properties, the XAML parser needs to perform a conversion. The conversion is performed by type converters, a basic piece of infrastructure that’s borrowed from the full .NET Framework.

Essentially, a type converter has one role in life—it provides utility methods that can convert a specific .NET data type to and from any other .NET type, such as a string representation in this case. The XAML parser follows two steps to find a type converter:

  1. It examines the property declaration, looking for a TypeConverter attribute. (If present, the TypeConverter attribute indicates what class can perform the conversion.) For example, when you use a property such as Foreground, .NET checks the declaration of the Foreground property.
  2. If there’s no TypeConverter attribute on the property declaration, the XAML parser checks the class declaration of the corresponding data type. For example, the Foreground property uses a Brush object. The Brush class (and its derivatives) uses the BrushConverter because the Brush class is decorated with the TypeConverter(typeof(BrushConverter)) attribute declaration.

Some classes define a content property, which allows you to provide the property value between the start and end tags. For example, the Button class designates Content as its content property, meaning this markup:

 <Button>Click Me!</Button>

is equivalent to this:

 <Button Content="Click Me!"></Button>

Complex Properties

XAML provides another option: property-element syntax. With property-element syntax, you add a child element with a name in the form Parent.PropertyName. For example, the Grid has a Background property that allows you to supply a brush that’s used to paint the area behind the elements. If you want to use a complex brush—one more advanced than a solid color fill—you’ll need to add a child tag named Grid.Background, as shown here:

 <UserControl x:Class="EightBall.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid x:Name="grid1">
<Grid.Background>
<LinearGradientBrush>
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0.00" Color="Yellow" />
<GradientStop Offset="0.50" Color="White" />
<GradientStop Offset="1.00" Color="Purple" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Grid.Background>
</Grid>
</UserControl>

Attached Properties

Attached properties always use a two-part name in this form: DefiningType.PropertyName. This two-part naming syntax allows the XAML parser to distinguish between a normal property and an attached property.

 <UserControl x:Class="EightBall.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid x:Name="grid1">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions> <TextBox x:Name="txtQuestion"
Grid.Row="0"
Text="[Place question here.]">
</TextBox> <Button x:Name="cmdAnswer"
Grid.Row="1"
Content="Ask the Eight Ball">
</Button> <TextBox x:Name="txtAnswer"
Grid.Row="2"
Text="[Answer will appear here.]">
</TextBox>
</Grid>
</UserControl>

Attached properties aren’t really properties at all. They’re actually translated into method calls. The XAML parser calls the static method that has this form: DefiningType.SetPropertyName(). For example, in the previous XAML snippet, the defining type is the Grid class, and the property is Row, so the parser calls Grid.SetRow().

When calling SetPropertyName(), the parser passes two parameters: the object that’s being modified and the property value that’s specified. For example, when you set the Grid.Row property on the TextBox control, the XAML parser executes this code:

 Grid.SetRow(txtQuestion, );

This pattern (calling a static method of the defining type) is a convenience that conceals what’s really taking place. To the casual eye, this code implies that the row number is stored in the Grid object. However, the row number is actually stored in the object that it applies to—in this case, the TextBox object.

This sleight of hand works because the TextBox derives from the DependencyObject base class, as do all Silverlight elements. The DependencyObject is designed to store a virtually unlimited collection of dependency properties (and attached properties are one type of dependency property).

In fact, the Grid.SetRow() method is actually a shortcut that’s equivalent to calling the DependencyObject.SetValue() method, as shown here:

 txtQuestion.SetValue(Grid.RowProperty, );

Nesting Elements

XAML allows each element to decide how it deals with nested elements. This interaction is mediated through one of three mechanisms that are evaluated in this order:

  1. If the parent implements IList<T>, the parser calls the IList<T>.Add() method and passes in the child.
  2. If the parent implements IDictionary<T>, the parser calls IDictionary<T>.Add() and passes in the child. When using a dictionary collection, you must also set the x:Key attribute to give a key name to each item.
  3. If the parent is decorated with the ContentProperty attribute, the parser uses the child to set that property.

Some properties might support more than one type of collection. In this case, you need to add a tag that specifies the collection class, like this:

         <Grid.Background>
<LinearGradientBrush>
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Offset="0.00" Color="Yellow" />
<GradientStop Offset="0.50" Color="White" />
<GradientStop Offset="1.00" Color="Purple" />
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Grid.Background>

Nested content doesn’t always indicate a collection. For example, consider the Grid element, which contains several other elements:

 <UserControl x:Class="EightBall.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid x:Name="grid1">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions> <TextBox x:Name="txtQuestion"
Grid.Row="0"
Text="[Place question here.]">
</TextBox> <Button x:Name="cmdAnswer"
Grid.Row="1"
Content="Ask the Eight Ball">
</Button> <TextBox x:Name="txtAnswer"
Grid.Row="2"
Text="[Answer will appear here.]">
</TextBox>
</Grid>
</UserControl>

These nested tags don’t correspond to complex properties, because they don’t include the period. Furthermore, the Grid control isn’t a collection and so it doesn’t implement IList or IDictionary. What the Grid does support is the ContentProperty attribute, which indicates the property that should receive any nested content. Technically, the ContentProperty attribute is applied to the Panel class, from which the Grid derives, and looks like this:

 [ContentPropertyAttribute("Children")]
public abstract class Panel : FrameworkElement

This indicates that any nested elements should be used to set the Children property. The XAML parser treats the content property differently depending on whether it’s a collection property (in which case it implements the IList or IDictionary interface). Because the Panel.Children property returns a UIElementCollection and because UIElementCollection implements IList, the parser uses the IList.Add() method to add nested content to the grid.

Events

In many situations, you’ll use attributes to set properties and attach event handlers on the same element. Silverlight always follows the same sequence: first it sets the Name property (if set), then it attaches any event handlers, and lastly it sets the properties. This means that any event handlers that respond to property changes will fire when the property is set for the first time.

XAML Resources

Silverlight includes a resource system that integrates closely with XAML. Using resources, you can do the following:

  1. Create nonvisual objects: This is useful if other elements use these objects. For example, you could create a data object as a resource and then use data binding to display its information in several elements.
  2. Reuse objects: Once you define a resource, several elements can draw on it. For example, you can define a single brush that’s used to color in several shapes. Later in this book, you’ll use resources to define styles and templates that are reused among elements.
  3. Centralize details: Sometimes, it’s easier to pull frequently changed information into one place (a resources section) rather than scatter it through a complex markup file, where it’s more difficult to track down and change.

The Resources Collection

Every element includes a Resources property, which stores a dictionary collection of resources. The resources collection can hold any type of object, indexed by string.

Although every element includes the Resources property, the most common way to define resources is at the page level. That’s because every element has access to the resources in its own resource collection and the resources in all of its parents’ resource collections. So if you define a resource in the page, all the elements on the page can use it.

         <LinearGradientBrush x:Key="BackgroundBrush">
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0.00" Color="Yellow" />
<GradientStop Offset="0.50" Color="White" />
<GradientStop Offset="1.00" Color="Purple" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</UserControl.Resources>

To use a resource in your XAML markup, you need a way to refer to it. This is accomplished using a markup extension—a specialized type of syntax that sets a property in a nonstandard way. Markup extensions extend the XAML language and can be recognized by their curly braces. To use a resource, you use a markup extension named StaticResource:

 <Grid x:Name="grid1" Background="{StaticResource BackgroundBrush}">

The Hierarchy of Resources

Every element has its own resource collection, and Silverlight performs a recursive search up your element tree to find the resource you want.

Order is important when defining a resource in markup. The rule of thumb is that a resource must appear before you refer to it in your markup.

Interestingly, resource names can be reused as long as you don’t use the same resource name more than once in the same collection. In this case, Silverlight uses the resource it finds first. This allows you to define a resource in your application resources collection and then selectively override it with a replacement in some pages with a replacement.

Accessing Resources in Code

 LinearGradientBrush brush = (LinearGradientBrush)this.Resources["ButtonFace"];

However, there’s one limitation. Because Silverlight doesn’t support dynamic resources, you aren’t allowed to change the resource reference. That means you can’t replace a resource with a new object. Here’s an example of code that breaks this rule and will generate a runtime error:

 SolidColorBrush brush = new SolidColorBrush(Colors.Yellow);
this.Resources["ButtonFace"] = brush;

Rather than dig through the Resources collection to find the object you want, you can give your resource a name by adding the Name attribute. You can then access it directly by name in your code. However, you can’t set both a name and a key on the same object, and the StaticResource markup extension recognizes keys only. Thus, if you create a named resource, you won’t be able to use it in your markup with a StaticResource reference. For that reason, it’s more common to use keys.

Organizing Resources with Resource Dictionaries

If you want to share resources between multiple projects or just improve the organization of a complex, resource-laden project, you can create a resource dictionary. A resource dictionary is simply a XAML document that does nothing but store a set of resources.

 <ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> </ResourceDictionary>

To use a resource dictionary, you need to merge it into a resource collection somewhere in your application. You could do this in a specific page, but it’s more common to merge it into the resources collection for the application, as shown here:

 <Application xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SilverlightApplication1.App">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ElementBrushes.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>

One reason to use resource dictionaries is to define the styles for application skins that you can apply dynamically to your controls. Another reason is to store content that needs to be localized (such as error message strings).

Element-to-Element Binding

One-Way Binding

 <Slider x:Name="sliderFontSize" Margin="3"
Minimum="1" Maximum="40" Value="10">
</Slider> <TextBlock Margin="10" Text="Simple Text" x:Name="lblSampleText"
FontSize="{Binding ElementName=sliderFontSize, Path=Value}" >
</TextBlock>

Data binding expressions use a XAML markup extension (and hence have curly braces). You begin with the word Binding, followed by any constructor arguments  and then a list of the properties you want to set by name—in this case, ElementName and Path. ElementName indicates the source element. Path indicates the property in the source element. Thus, this binding expression copies the value from the Slider.Value property to the TextBlock.FontSize property.

Tip:The Path can point to a property of a property (for example, FontFamily.Source) or an indexer used by a property (for example, Content.Children[0]). You can also refer to an attached property (a property that’s defined in another class but applied to the bound element) by wrapping the property name in parentheses. For example, if you’re binding to an element that’s placed in a Grid, the path (Grid.Row) retrieves the row number where you’ve placed it.

备注:在单向绑定中,如果用代码修改了绑定目标的属性值,目标属性的绑定就会消失(得查查为啥这样设计)。

Two-Way Binding

Interestingly, there’s a way to force values to flow in both directions: from the source to the target and from the target to the source. The trick is to set the Mode property of the Binding to TwoWay.

Silverlight:《Pro Silverlight5》读书笔记 之 XAML的更多相关文章

  1. Pro mvvm读书笔记mvvm中的VM

    一.构建ViewModels 设计模式的其中一个目标就是抽象构造一个给出指定类型的对象或者实现指定类型的接口的过程.需要把类给客户端,让客户端去使用,但是要隐藏类是具体的实现细节. 1.1The Ap ...

  2. pro mvvm 读书笔记

    一.分离关注点 目的是确保每一个模块值有单一的,明确的目的,不需要去负责其他的功能.单一的目的也称为关注点. 1.1依赖 引用程序集对于依赖来说不是必须的.依赖关系可能也存在于一个代码单元要知道另一个 ...

  3. Pro Git 读书笔记

    一. 起步 1. 集中式版本控制缺点:中央服务器的单点故障. 分布式版本控制优点:客户端并不只提取最新版本的文件快照,而是把代码仓库完整地镜像下来. 这么一来,任何一处协同工作用的服务器发生故障,事后 ...

  4. Pro Git读书笔记 - 分支

    Git 分支介绍. 几乎所有的版本控制系统都以某种形式支持分支. 使用分支意味着你可以把你的工作从开发主线上分离开来,以免影响开发主线. 在很多版本控制系统中,这是一个略微低效的过程--常常需要完全创 ...

  5. Pro Git读书笔记 - Git 常用命令

    在工作目录中初始化新仓库 要对现有的某个项目开始用 Git 管理,只需到此项目所在的目录,执行git init 检查当前文件状态 要查看哪些文件处于什么状态,可以用git status命令 将工作文件 ...

  6. pro git 读书笔记 3 Git 分支

    分支 新建分支:git branch 分支名 切换到该分支:git checkout 分支名 补充:以上两条语句等价于一句:git checkout -b 分支名 转换分支的时候最好保持一个清洁的工作 ...

  7. pro git 读书笔记 1

    Git 1 - Getting Started Git 的特点 Git 存储每个版本的快照:其他 VCS(版本控制系统) 存储两个版本的变化之处 好处参考 Git 分支章节 Git 几乎所有操作都是本 ...

  8. pro git 读书笔记 2

    Git 2 - Git Basics 1 add github 上建立新的 repository,命名 demo git clone 到本地 github 目录 将自己之前的项目 copy 到该 de ...

  9. WPF,Silverlight与XAML读书笔记第四十八 - Silverlight网络与通讯

    说明:本系列基本上是<WPF揭秘>的读书笔记.在结构安排与文章内容上参照<WPF揭秘>的编排,对内容进行了总结并加入一些个人理解. 这一部分我们重点讨论下Silverlight ...

随机推荐

  1. 看懂 MySQL 慢查询日志

    MySQL中的日志包括: 错误日志.二进制日志.通用查询日志.慢查询日志等等. 这里主要介绍下比较常用的两个功能:通用查询日志和慢查询日志. 1)通用查询日志:记录建立的客户端连接和执行的语句. 2) ...

  2. python抓取链家房源信息(二)

    试着用scrapy将之前写的抓取链家网信息的重新写了写 然后先是用了第一页的网页作为测试,调试代码,然后发现总是抓取的时候遇见了 类似于这样的问题,并且抓取不到信息 2017-03-28 17:52: ...

  3. MySQL增删改数据

    1.增加数据 ,); /*插入所有字段.一定依次按顺序插入--字符串与日期需要加单引号,数字不需要,各个字段之间用逗号分隔*//*注意不能少或者多字段值*/ ,) /*按字段名插入数据,中间用逗号隔开 ...

  4. n*m的矩阵,行和列都递增有序,求是否出现target元素(面试题)

    题目描述:给定一个n*m的矩阵,矩阵的每一行都是递增的,每一列也是递增的,给定一个元素target,问该target是否在矩阵中出现. 思路:先从最左下角的元素开始找,三种情况: 1. 如果该元素大于 ...

  5. Js~对数组的操作

    在工作中可能用的不多,但一些特殊的场合还是会用到,所以在这里,把JS的数组操作总结一下,分享给大家! Array 对象 Array 对象用于在单个的变量中存储多个值. 创建 Array 对象的语法: ...

  6. 【LOJ】 #2008. 「SCOI2015」小凸想跑步

    题解 一道想法很简单的计算几何(由于我半平面交总是写不对,我理所当然的怀疑半平面交错了,事实上是我直线建错了) 首先我们对于两个凸包上的点设为\((x_0,y_0)\)和\((x_1,y_1)\)(逆 ...

  7. 【LOJ】 #2521. 「FJOI2018」领导集团问题

    题解 这道题很显然可以想出来一个\(n^2\)的dp,也就是dp[u][i]表示以u为根的子树最大值是i的点集最大是多少(i是离散化后的值) 就是对于每个儿子处理出后缀最大值然后按位相加更新父亲,我们 ...

  8. Vugen 和controller 中的run-time setting区别

    Vugen 和controller 中的run-time setting有什么不同?

  9. ubuntu 防火墙关闭的80端口,开启方法

    #关闭防火墙 /etc/init.d/iptables stopservice iptables stop # 停止服务#查看防火墙信息/etc/init.d/iptables status #开放端 ...

  10. 竹间智能科技(Emotibot)

    竹间智能简仁贤:表情识别准确率达到81.57%,语义理解是主要的商用落地场景 北京-招聘机器学习(实习生) 深圳-招聘图像识别工程师