蝈蝈俊.net

-- 用随笔来记录自己的技术感触

   博客堂 :: 首页 :: 联系 :: RSS 2.0 ::
随笔 - 669, 评论 - 4804, 引用 - 276

导航

关于

这里是我的技术Blog,下一代CSDN社区Blog在 http://blog.csdn.net/ghj1976/

标签

每月存档

最新留言

广告

Silverlight 版的华容道游戏

游戏如下:

 

你也可以访问这个地址来玩:

http://ghj1976.blob.core.windows.net/silverlight/TestPage_SilverlightApp_HuaRongDao_v1.html

游戏说明:

更多功能可以自己来试玩。

游戏的代码在:

http://ghj1976.blob.core.windows.net/silverlight/Solution_HuaRongDao_v1.zip

是使用 VS2010 Beta编写的,这是我学习Silverlight写的一个例子,代码并不优雅,见谅。

posted on 2010-03-08 16:15:16 by ghj1976  评论(1) 阅读(1481)

Silverlight 资源的使用

我们在Silverlight 项目中,新加一个文件,比如一个图片文件,这个文件的属性会有下面2个选项,这两个选项决定了这个图片资源如何存储,如何使用。

先说简单的,资源文件的 Copy to OutPut Directory 属性, 这个属性有如下三个选项:

image

他们都是在程序编译或者部署时,判断此资源文件是否要同步用的。

Do not copy 不做数据同步
Copy always 每次都会被同步过去
Copy if newer 当有新版本存在时,才会被同步过去

 

Build Action 属性则复杂多了, 下面是VS2010中, Silverlight 4 项目资源文件的Build Action 属性截图。

image

注意,上面罗列了一些不适合资源文件的 Build Action 属性,在使用资源文件时,可以忽略这些。

 

None 资源既不会被集成到程序集内,也不会打包到xap包中。不过我们可以通过设置CopyToOutputDirectory选项让其自动拷贝到xap包所在目录。
这种情况下, 访问这个图片的相对Uri需要以"/"开始。

适用场景:

在大多数情况下,我们希望把video/audio文件放到xap的外面,因为这种文件一般都比较大,会影响silverlight应用的加载,而且一般的视频音频文件都是压缩格式的,放到xap中也不会起到减少他们文件大小的作用。
类似图片视频这种资源文件生成操作为None时和他们没有被添加到项目里是一样的,都可以用绝对Uri进行引用。

Compile 不适合用于资源文件。
类文件要用"Compile"生成操作, 就是指项目里.cs或.vb文件。
Content 资源会被打包在Xap包里面。
这种情况下, 访问这个图片的相对Uri需要以"/"开始。
在这种方式下,如果没有在xap中找到图片文件,那么silverlight会自动从当前xap应用所在的文件夹下来找所需图片文件,
如果还没有找到那么就触发ImageFailed事件,
这种方式比较适合在多个程序集引用相同文件时采用。
Embedded Resource

这种方式会把文件嵌入到程序集中,silverlight无法通过Uri引用在xaml和c#里对这个文件进行使用,微软不建议在silverlight采用这种方式在程序集里嵌入资源。
如果有这种需求可以用
Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(string path)相关的方法得到文件的stream引用。

ApplicationDefinition

silverlight程序的入口xaml文件(默认就是App.xaml)应该设置为这个"应用定义"。其他文件都不适合用这个。

Page 不适合用于资源文件。
所有的用户控件, 页面和子窗体(usercontrol/page/childwindow)的xaml文件应该采用的生成操作。
如果改为别的方式那么会导致后台对应的代码文件无法链接到这个xaml文件。 采用"Page" build action时xaml里的错误会导致工程无法正确生成。
CodeAnalysisDictionary 代码分析使用,Silverlight中可以忽略
Resource 资源会被打包在程序集内部。
选择这种生成方式后,该资源文件会被嵌入到该应用的程序集中,就是说打开生成的xap是看不到这个文件的。

可以用相对于当前的XAML文件的相对Uri访问,
如<Image Source="silverlight.png" />
或是<Image Source="./silverlight.png" />,

在子文件夹里的可以用
<Image Source=”./images/sl.jpg” />访问到。

最保险的方式是采用特有的程序集资源URI访问,格式为
<Image Source="/{assemblyShortName};component/Foo.jpg"/>,

这种方式还可以引用到xap中的其他程序集中的图片。

这种生成方式的系统资源可以直接用Application.GetResourceStream(uri).Stream在代码里来得到。

SplashScreen

"SplashScreen"是这个选项是WPF的启动画面使用的。  silverlight启动加载画面是用的其他方式实现的, 所以在silverlight里不要用这个方式。

EntityDeploy 这个是EntityFramework采用的生成方式, 在silverlight里是没用。

 

参考资料:

分析silverlight里的URI引用资源文件的各种情况
http://bbs.blueidea.com/viewthread.php?tid=2941697

Silverlight图片相对路径的设置
http://www.cnblogs.com/yangfan/archive/2009/12/14/1623647.html

关于Silverlight资源文件(如:图片)的放置位置及其引用(相对路径)
http://www.cnblogs.com/star250/archive/2009/10/15/1583665.html

Silverlight资源文件
http://msdn.microsoft.com/zh-cn/library/cc296240(VS.95).aspx

图片等资源的引用路径问题
http://www.cnblogs.com/kevinyang/archive/2008/11/16/1334712.html

posted on 2010-03-08 10:24:21 by ghj1976  评论(0) 阅读(1267)

我眼中的VS2010

VS2010正式版马上就要发布了,从09年国庆节后开始使用VS2010 Beta2测试版,到现在也已4个月了,VS2010的的变化很大,但是给我带来比较大影响的反而是几个小的功能变革。

VS2010改变了我对WPF观念

在听说VS2010是WPF开发之前,我总觉得WPF由于要实现这么多绚丽的界面,在性能上肯定损耗的不少。在之前,由于对美好界面的渴望,我也自己学习过WPF,由于公司日常工作用不到WPF,也就是写写小程序玩玩,但是能用WPF来开发VS2010,在此之前我是无论如何都没有想到的,非常吃惊,这就是我当初听到VS2010要用WPF来开发的感受。在使用VS2010这么久后,VS2010测试版虽然有时候会时不时没有响应,但是它的速度,性能,一点都不比我装在同一台机子上的VS2008差。VS2010 RC 版据说解决了那些没有响应的问题,同时速度优化了很多,由于我要用到Silverlight 4 的开发,就没装 VS2010 RC 版,VS2010的正式版确实很值得期待。网上说 VS2010 RC 版对性能的改进体验非常深刻,参看:.NET 4 RC版 发布了 这篇博客。

代码智能提示的改进

.NET Framework 的函数库越来越强大,也越来越多,不是特长常用的,函数名确实难以记住,VS2008 开发环境的智能提示是根据方法或者属性的起始字母来选择的,如下图所示:

image

VS2010中则搜索的是包含搜索词的所有函数和属性。这样如下图所示,我们搜索 edit ,不仅仅可以搜索出 EditIndex,还可以搜索出字母中间带Edit的方法,属性,事件。

image

这样,那些我们没有精确记忆的属性和方法就会出现在智能提示中,对我们的编程非常方便实用。

有关这方面的内容你可以参看: VS 2010 和 .NET 4.0 系列之《VS 2010代码智能提示的改进》篇

 

导航和查询代码的改进

当我们阅读一个代码非常膨大,而不是又不是特别熟悉它的代码结构时,如何找到并定位代码,会是一个难题。这个功能VS2010新增的功能对我们非常有用。如下图:(Ctrl+逗号)的键盘快捷键就可以打开下面的“Navigate To(导航到)”对话框。在Search terms 中我们输入2个关键字:“cache action”,就可以搜索出包含这两个关键字的方法,类,属性,事件。这跟上面的智能提示一样,是包含,而不是以某个字开头。

image_thumb_7E22DE68

有关这方面的内容你可以参看: VS 2010 和 .NET 4.0 系列之《在VS 2010中查询和导航代码》篇

 

鼠标滚轮滚动,对应字体大小的变化

这个功能对演示代码非常有帮助,比如公司内部,我在给大家演示一些代码时,由于现在的屏幕分辨率越来越大,我又习惯用最大的分辨率,这样稍稍离我远点的,就看不清楚编辑器的内容,以前我是在演示时,修改VS开发环境编辑器的默认字体大小,不演示了,再改回去,现在我不需要反复的改来改去,直接用鼠标中键滚轮来回滚动,就可以轻松实现字体的放大和缩小,非常实用,非常方便,我经常使用它。

使编程更容易;让我们对WPF更有信心。这就是我对VS2010的感觉。

posted on 2010-03-08 09:21:03 by ghj1976  评论(0) 阅读(1678)

WPF/Silverlight 控件的几幅继承关系图

图均来自网络,如下,这几幅图对理解控件的继承关系很有帮助:

image_3

DispatcherObject: WPF/Silverlight 中有许多类继承自DispatcherObject,DispatcherObject提供了处理同步和并发的基本构造。

DependencyObject :构建WPF/Silverlight的一个主要思想是属性优先于方法和事件。WPF/Silverlight 提供了丰富的属性系统,其核心是DependencyObject。

Visual:该类的主要作用是为WPF/Silverlight 提供2D呈现支持,主要包括输出显示,坐标转换,区域剪切等。

UIElement:该类继承自Visual类,是构建WPF/Silverlight元素和基本呈现特征的基类,其中定义很多与输入和焦点有关的特性,例如键盘事件,鼠标,还包括一些与WPF事件模型有关的API。

FrameworkElement:继承了UIElement类,而且还添加了一些功能,例如,布局定义、逻辑树、对象生命周期事件、支持数据绑定和动态资源引用、支持样式和动画。

image3

Control是创建自定义应用程序控件的基类。可以重写Control类所提供的属性,方法,事件等,为自定义控件添加自定义逻辑。 构建WPF/Silvlerlight  应用程序页面的window类就派生自它.还有button,TextBox等控件也派生自他。

Shape:WPF/Silvlerlight 中呈现二维矢量图形的基础类。有 Line、Polyline、Polygon、Path、Rectangle 和 Ellipse等子类。可从 Shape 类进行派生以实现自定义矢量图形基元。从 Shape 派生是确保这些自定义基元使用 WPF/Silvlerlight 布局系统的协议的最简单方法。

posted on 2010-02-07 18:01:30 by ghj1976  评论(0) 阅读(1707)

DependencyProperty

和传统属性的区别在哪里,为什么要搞出这样一个DependencyProperty呢?

在 MSDN 中,提到当你有下面四种情况时,应该考虑使用DependencyProperty:

 

一个Silverlight中创建 DependencyProperty 的例子

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Media.Imaging;

namespace SilverlightApplication2
{
    public partial class SilverlightControl1 : UserControl
    { 

        /// <summary>
        /// Declare the dependency property as static, readonly field in your class.    
        /// </summary>
        public static readonly DependencyProperty AquariumGraphicProperty 
            = DependencyProperty.Register(
          "AquariumGraphic",                                        // Property name
          typeof(Uri),                                              // Property type
          typeof(SilverlightControl1),                              // Type of the dependency property provider
          new PropertyMetadata(null,                                // 默认的值
              new PropertyChangedCallback(OnUriChanged)               // Callback invoked on property value has changes
          )
        );

        /// <summary>
        /// Create the property and use the SetValue/GetValue methods of the DependencyObject class
        /// </summary>
        public Uri AquariumGraphic
        {
            get { return (Uri)GetValue(AquariumGraphicProperty); }
            set { SetValue(AquariumGraphicProperty, value); }
        }
             
        public SilverlightControl1()
        {
            InitializeComponent();
        }        
     
        /// <summary>
        /// 值变化时,更新显示
         /// </summary>
        /// <param name="d"></param>
        /// <param name="e"></param>
        private static void OnUriChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Shape sh = (Shape)d;
            ImageBrush ib = new ImageBrush();
            ib.ImageSource = new BitmapImage(e.NewValue as Uri);
            sh.Fill = ib;
        }

     
    }
}

我们首先来看看 AquariumGraphicProperty ,类型就是DependencyProperty,前面用了static readonly,一个单例模式,有DependencyProperty.Register,看起来像是往容器里注册,其实也差不多。

再来看AquariumGraphic,和传统的属性没什么区别,类型是 Uri 型,有get,set方法。只不过内部的实现分别调用了GetValue和SetValue,这两个方法是DependecyObject(简称DO,是WPF/Silverlight中所有可视Visual的基类)暴露出来的,传入的参数是AquariumGraphicProperty。

需要注意的是运行时,Xaml中是直接调用GetValue和SetValue的。所以,为了让使用XAML设置属性与使用代码设置属性一致,在属性包装器中除了GetValue和SetValue调用以外,不应该包含任何其他逻辑,这是非常重要的。如果需要添加自定义逻辑,应该在Register的回调函数中添加。

 

参考资料:

.Net3.0里的DependencyProperty(1):引入了DP的一些基本概念
http://www.cnblogs.com/yayx/archive/2007/05/26/761117.html

WPF里的DependencyProperty(2):DP的应用,主要想解释我们为什么要用它
http://www.cnblogs.com/yayx/archive/2008/04/20/1162963.html

WPF里的DependencyProperty(3):主要想演示下怎么用DP
http://www.cnblogs.com/yayx/archive/2008/04/22/1166064.html

WPF/Silverlight为什么要使用Canvas.SetLeft()这样的方法? :附属,从布局应用上解释了下为什么要有AttachedProperty
http://www.cnblogs.com/yayx/archive/2008/04/23/1167110.html

WPF里的DependencyProperty(4):介绍了DP的工作机制
http://www.cnblogs.com/yayx/archive/2008/04/24/1168738.html

WPF里的DependencyProperty(5) :介绍了PropertyMetadata和AttachedProperty
http://www.cnblogs.com/yayx/archive/2008/06/03/1213126.html

Windows Presentation Foundation 体系结构
http://msdn.microsoft.com/en-us/ms750441(zh-cn).aspx

如何学好WPF
http://www.cnblogs.com/zhouyongh/archive/2009/07/31/1536000.html

Tip: How to declare a dependency property in Silverlight?
http://www.silverlightshow.net/tips/Tip-How-to-declare-a-dependancy-property-in-Silverlight.aspx

WPF体系结构-- System.Windows.DependencyObject与智能的控件
http://bbniu.com/forum/thread-478-1-1.html

图解DotNet框架之九:WPF
http://www.cnblogs.com/xugao918/archive/2008/08/01/1258193.html

Silverlight自定义依赖项对象和依赖项属性
http://msdn.microsoft.com/zh-cn/library/cc903933(VS.95).aspx

posted on 2010-02-07 16:35:41 by ghj1976  评论(0) 阅读(1698)

Blend 的两个选择工具简单对比

我们使用Blend 设计WPF或者Silverlight 界面是,会看到有两个选择工具,下面就是他们的对比。

  选择工具 路径选择工具
截图 image image
英文名称 Selection Direct Selection
作用 在美工板上选择要修改的形状、路径和对象。跟普通的选择鼠标一样 显示在绘制路径上的节点,并对各个节点进行操作。
  如下图所示,选择这个元素的整体 对非Path对象来说,就是选择整体,对Path对象来说如下,可以选择Path的每一个关键点,并对他们进行设置。
对路径的处理 image image
鼠标操作 如上图所示,移动对象的位置。 当鼠标在Path上移动时,可能是下面五种鼠标,对应的是五种功能。
image
移动点指针,用于 使路径上的点显示切线图柄 方法就是: 单击路径上的点 或者 用于 移动路径上的点 方法就是: 拖动路径上的点;
image 移动段指针,用于 使路径上两点之间的段显示切线图柄 方法就是 单击路径段 或者 用于 移动路径上两点之间的段 方法就是 拖动路径段;
image 移动切线指针,用于 更改路径上的点的切线角度 方法就是 单击路径上的点或线段以显示切线图柄,然后拖动其中一个切线端点
image 转换点指针,用于 使点成为锐角,或者将切线的长度缩短为零 或者 使任何锐角变得平滑(或者,如果已经平滑,则通过单击点来更改曲线的角度); 方法就是: 悬停在某个点上,按住 Alt,然后拖动此点
image 转换段指针,用于 将曲线段改为直线段 或者 获取一条段,并使其弯曲通过指针位置, 方法就是 : 悬停在路径中的某条线段上,按住 Alt,然后拖动线段;
也可以 独立于另一边调整切线的一端 ,方法就是: 直接选择一个点或一条线段,按住 Alt,然后拖动一个切线端点。

注:若要添加或删除现有路径上的点,或者连接两个现有路径,请使用"笔"工具。

上面我们可以看到 , 路径选择工具 跟笔工具息息相关。下面是笔工具的一些用法。

 

image 笔指针

创建直线段的起点,方法: 单击以创建新点;

创建曲线段的起点,方法: 单击以创建新点,然后拖动以调整切线图柄,最后再松开鼠标按钮;

 

image  笔调整指针

调整最后一条切线时不应用平滑约束,因此可以生成锐角,方法: 单击以创建新点,然后按 Alt,最后再松开鼠标按钮;

分割最后一条切线,使切线的端点保持独立,因此可以生成锐角,方法: 单击以创建新点,然后按下 Alt 并拖动,最后再松开鼠标按钮;

按 15 度的增量在新点周围移动切线端点,方法: 单击以创建新点,然后按下 Shift+Alt 并拖动,最后再松开鼠标按钮;

在一个端点处将切线长度减小为零, 方法: 单击该端点;

 

 image 笔插入指针

向现有路径添加新点,方法: 单击路径中需要新点的位置;

 

image  笔删除指针

从路径中删除点,方法: 悬停在现有点上并单击;

 

image 笔封闭指针

用锐角封闭路径,方法: 单击该起点;

在角部用平滑曲线封闭路径,方法: 单击起点并拖动以修改切线图柄,然后松开鼠标按钮;

 

image  笔连接指针

连接两条路径时创建锐角,方法: 选择两条路径,依次单击"笔"工具、一条路径的端点以及另一条路径的端点;

连接两条路径时创建平滑角点,方法: 选择两条路径,依次单击"笔"工具和一条路径的端点,然后拖动另一条路径的端点;

 

image  笔开始指针

新建路径,方法: 按下 Ctrl 并在前一条路径的外部单击,以停止向前一条路径中添加点,然后在所需的新路径开始位置单击或拖动;

posted on 2010-01-25 14:45:23 by ghj1976  评论(0) 阅读(2052)

Silverlight 样式

WPF 和 Silverlight 支持 Style 机制,它允许我们把控件的属性值封装成可重用的资源。我们可以把这些样式声明保存在独立于页面的其他文件中(当然本文件也可以),然后就可以在一个应用程序中跨控件和页面重用(甚至跨多个应用程序重用)。在做一些基本定制的场景下,概念上类似于在 HTML 中重用 CSS。

 

一个样式的简单例子

我们给一个园定义一个名叫 EllipseStyle1 的样式,然后应用这个样式。

Xaml 文件

<UserControl
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	x:Class="SilverlightApplication_Style.MainPage"
	Width="300" Height="300">
	<UserControl.Resources>
		<Style x:Key="EllipseStyle1" TargetType="Ellipse">
			<Setter Property="Fill">
				<Setter.Value>
					<LinearGradientBrush EndPoint="0.9,1" StartPoint="0.1,0.1">
						<GradientStop Color="#FF42B34A" Offset="0"/>
						<GradientStop Color="#FFC03535" Offset="1"/>
					</LinearGradientBrush>
				</Setter.Value>
			</Setter>
			<Setter Property="Margin" Value="10,0,0,0"/>
			<Setter Property="Cursor" Value="Hand"/>
			<Setter Property="StrokeThickness" Value="20"/>
			<Setter Property="VerticalAlignment" Value="Center"/>
			<Setter Property="HorizontalAlignment" Value="Center"/>
		</Style>
	</UserControl.Resources>

	<Grid x:Name="LayoutRoot" Background="White">
		<Ellipse Height="100" Width="100" Style="{StaticResource EllipseStyle1}" />
	</Grid>
</UserControl>

效果图:

image

这里简单期间把样式跟控件放在一个文件中了, 实际我们还可以放在另外一个文件。

使用 Blend 设计样式时,我们会看得更清楚,

使用菜单在 对象 –> 编辑样式 –> 创建空项 打开创建 Style 资源时,我们就可以看到我们可以在多个地方保存样式:

image

之后在 Blend 中编辑时,可以在资源中选择对应的样式名字,然后如下图所示进行编辑:

编辑可以在属性窗口修改任何想修改的内容。

image

在编辑完毕后,在对象和时间线中,点击 image 按钮就可以回到正常状态。

image

参考资料:

Silverlight教程第四部分:使用 Style 元素更好地封装观感
http://blog.joycode.com/scottgu/archive/2008/02/29/114915.joy

一步一步学Silverlight 2系列(8):使用样式封装控件观感
http://www.cnblogs.com/Terrylee/archive/2008/03/08/Silverlight2-step-by-step-part8-styles.html

解说:Silverlight Style,Setter(XAML/Design)换肤机制
http://blog.csdn.net/bobby96333/archive/2008/10/22/3126363.aspx

Silverlight2 边学边练 之六 设定风格
http://www.cnblogs.com/gnielee/archive/2009/08/02/1537122.html

Silverlight 2 : 关于ListBox的一个Layout Bug及其解决方法
http://www.cnblogs.com/sun/archive/2009/03/04/1402648.html

Silverlight项目中"自定义控件开发/Style"学习笔记
http://www.cnblogs.com/yjmyzz/archive/2009/11/11/1600791.html

Quick Silverlight Tip: Define control style dynamically
http://blogs.microsoft.co.il/blogs/alex_golesh/archive/2008/09/09/quick-silverlight-tip-define-control-style-dynamically.aspx

posted on 2009-12-30 17:16:40 by ghj1976  评论(1) 阅读(2226)

Silverlight 动画与定时器

动画和定时器是紧密相关的,下面的三个例子既可以说是定时器,也可以说是动画。

 

编码使用定时器

编码方式使用定时器,最简单的就是使用 System.Windows.Threading 命名空间的 DispatcherTimer 类。虽然也可以用 System.Timers.Timer,但是实现就会复杂多了,不推荐使用System.Timers.Timer,原因如下:

在每个 Dispatcher (管理线程工作项队列的服务)循环的顶端重新计算 DispatcherTimer。 这样 DispatcherTimer 不能保证会正好在时间间隔发生时执行计时器,但能够保证不会在时间间隔发生之前执行计时器。 这是因为 DispatcherTimer 操作与其他操作一样被放置到 Dispatcher 队列中。 何时执行 DispatcherTimer 操作取决于队列中的其他作业及其优先级。

如果 System.Timers.Timer 用于 WPF/Silverlight 应用程序,则值得注意的是 System.Timers.Timer 运行于不同于用户界面 (UI) 线程的其他线程上。 为了访问用户界面 (UI) 线程上的对象,需要使用 Invoke 或 BeginInvoke 将操作发布到用户界面 (UI) 线程的 Dispatcher 上。

使用 DispatcherTimer 而不是使用 System.Timers.Timer 的原因是 DispatcherTimer 与 Dispatcher(管理线程工作项队列的服务) 运行于相同的线程,并且可以在 DispatcherTimer 上设置 DispatcherPriority。

使用 DispatcherTimer 的例子

XAML 文件

<Grid x:Name="LayoutRoot" Background="White">
  <TextBlock Loaded="StartTimer" x:Name="myTextBlock" />
</Grid>

代码文件

public void StartTimer(object o, RoutedEventArgs sender)
{
    System.Windows.Threading.DispatcherTimer myDispatcherTimer = new System.Windows.Threading.DispatcherTimer();
    myDispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, 100); // 100 Milliseconds 
    myDispatcherTimer.Tick += new EventHandler(Each_Tick);
    myDispatcherTimer.Start();
}

// A variable to count with.
int i = 0;

// Raised every 100 miliseconds while the DispatcherTimer is active.
public void Each_Tick(object o, EventArgs sender)
{
    myTextBlock.Text = "Count up: " + i++.ToString();
}

 

使用故事版来做的定时器

我们在 Storyboard  的 Completed 事件中再次把Storyboard 起来:  myTimer.Begin();  这就相当于一个定时器。

XAML文件

<UserControl
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	x:Class="MySilverlight3Study_Animation3.MainPage"
	Width="180" Height="120">
	<UserControl.Resources>
		<Storyboard x:Name="myTimer" Duration="00:00:01"  Completed="myTimer_Completed" />  
 	</UserControl.Resources>
	<Grid x:Name="LayoutRoot" Background="White">
	<Grid.RowDefinitions>
		<RowDefinition/>
		<RowDefinition/>
	</Grid.RowDefinitions>
	
	<Button x:Name="btn" Height="36" Margin="20,5"  Content="开始" Grid.Row="1" 
		Click="Button_Click"/>
	<TextBlock x:Name="txt" Grid.Row="0" Height="40" Width="60" Text="0" 
		TextWrapping="Wrap" Foreground="#FFA72222" FontSize="26.667" 
		FontFamily="Comic Sans MS" FontWeight="Bold" TextAlignment="Center" 
		LineHeight="9.333"/>
	</Grid>
</UserControl>

代码文件

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace MySilverlight3Study_Animation3
{
	public partial class MainPage : UserControl
	{
		public MainPage()
		{
			// 为初始化变量所必需
			InitializeComponent();
		}

		private bool isStop = true;
		
		
		private void Button_Click(object sender, System.Windows.RoutedEventArgs e)
		{
			if(isStop)
			{
				btn.Content = "暂停";
				myTimer.Begin();
			}
			else
			{
				btn.Content = "继续";
				myTimer.Stop();
			}
			isStop = !isStop;
		}
		
		private int i = 0;   
		
		private void myTimer_Completed(object sender, EventArgs e) 
		{
			i++;
			txt.Text = string.Format("{0}",i);
			myTimer.Begin();
		}
	}
}

 

用 CompositionTarget.Rendering 来做动画和定时器

除了之前提到的几种动画方式,还有一种只能使用代码创建的基于帧的动画方式。需要做的全部工作是响应静态的 CompositionTarget.Rendering 事件,触发该事件是为了为每帧获取内容。这是一种非常低级的方法,除非使用标准的基于属性的动画模型不能满足需要(例如,构建一个简单的游戏、创建一个基于物理的动画,或者构建粒子效果模型(如火焰、雪以及气泡)),否则不会希望使用这种方法。

构建基于帧的动画的基本技术很容易。只需要简单地为静态的CompositionTarget.Rendering事件关联事件处理程序。一旦关联了事件处理程序,Silverlight就会开始不断地调用这个事件处理程序(只要渲染代码执行得足够快,每秒将会调用60次)。

下面是一个简单的演示代码:

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace MySilverlight3Study_Animation3
{
	public partial class MainPage : UserControl
	{
		public MainPage()
		{
			// 为初始化变量所必需
			InitializeComponent();
			
			System.Windows.Media.CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);   
		}

		void CompositionTarget_Rendering(object sender, EventArgs e)
                {
			txt.Text = DateTime.Now.ToString();
		}
	}
}

Xaml 文件

<UserControl
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	x:Class="MySilverlight3Study_Animation3.MainPage"
	Width="180" Height="120">
	<TextBlock x:Name="txt" Text="1" Margin="20" Foreground="Red" TextAlignment="Center" />
</UserControl>

一般游戏,为了性能,都是使用  CompositionTarget.Rendering  事件来做的。而不是之前的2种方式。

 

参考资料:

SilverLight Timers, what to use?
http://advertboy.wordpress.com/2007/08/11/silverlight-timers-what-to-use/

在Silverlight中使用定时器(Timer)
http://blog.csdn.net/SilverlightShanghai/archive/2007/09/02/1768874.aspx

Silverlight 2 手把手(之六) 使用故事版实现定时器
http://blogs.msdn.com/jijia/archive/2008/04/30/silverlight2-timer-storyboard.aspx

Silverlight 2 手把手(之五) 编程实现定时器
http://blogs.msdn.com/jijia/archive/2008/04/29/programming-timer.aspx

How to: Create a Timer
http://msdn.microsoft.com/en-us/library/cc189084(VS.95).aspx

Make a Silverlight Timer (Silverlight 2)
http://blogs.msdn.com/silverlight_sdk/archive/2008/03/27/make-a-silverlight-timer-silverlight-2.aspx

21.4.5 基于帧的动画
http://book.51cto.com/art/200908/145560.htm

Silverlight: How to use CompositionTarget.Rendering event to synchronize discrete and non-discrete animations

http://blogs.msdn.com/marlat/archive/2009/05/24/silverlight-use-compositiontarget-rendering-event-to-synchronize-discrete-and-non-discrete-animations.aspx

CompositionTarget.Rendering事件
http://blog.etvalley.com/index.php/archives/tag/compositiontargetrendering

Silverlight制作逐帧动画 v2 - part1
http://www.cnblogs.com/nasa/archive/2009/09/11/imageBrush-Animate.html

Silverlight制作逐帧动画 v2 - part2
http://www.cnblogs.com/nasa/archive/2009/09/12/imageBrush-Animate-part2.html

Silverlight制作逐帧动画 v2 - part3
http://www.cnblogs.com/nasa/archive/2009/09/13/imageBrush-Animate-part3.html

Blend基础-动画
http://www.cnblogs.com/nasa/archive/2009/11/03/Expression_Blend_Essentials_Animation.html

posted on 2009-12-23 17:12:24 by ghj1976  评论(0) 阅读(2087)

Silverlight学习笔记--动画效果-- 关键帧动画

按照动画的形成方式,Silverlight 动画可以分为两种:

渐变式动画的讲解请看博客: Silverlight学习笔记--动画效果-- 渐变风格方式动画 本文介绍关键帧动画:

与渐变(From/To/By )动画类似,关键帧动画以动画形式显示了目标属性的值。它通过定义其持续时间(Duration属性)创建其目标值之间的过渡。但是,与From/To/By 动画创建两个值之间的过渡不同,单个关键帧动画可以创建任意数量的目标值之间的过渡。

与 From/To/By 动画不同,关键帧动画没有设置其目标值所需的 From、To 或 By 属性。而是使用关键帧对象描述关键帧动画的目标值。若要指定动画的目标值,需要创建关键帧对象并将其添加到动画的 KeyFrames 属性。动画运行时,将在您指定的帧之间过渡。

 

几种关键帧动画的动画过度方法(Interpolation Methods)

关键帧动画从一帧到另外一帧,是如何过度的,这个过度策略就是 Interpolation Methods ,MSDN上的翻译竟然叫“内插方法”,我晕,翻译真垃圾。这个过度策略有三种方式:线性(linear interpolation 线性内插)、离散(Discrete Interpolation  离散内插)和样条(Splined Interpolation 样条内插)。

 

linear interpolation 线性

使用线性过度,指定时间段内,动画的播放速度将是固定的。比如,如果关键帧段在 5 秒内, 从 0 过渡到 10,则该动画会在指定的时间产生如下表所示的值。

时间 输出值
0 0
1 2
2 4
3 6
4 8
4.25 8.5
4.5 9
5 10

Discrete Interpolation  离散

使用离散过度,动画函数将从一个值跳到下一个没有内插的值。如果关键帧段在 5 秒内从 0 过渡到 10,则该动画会在指定的时间产生如下表所示的值。动画在持续期间恰好结束之前不会更改其输出值,一直到到了时间点,才会修改。

时间 输出值
0 0
1 0
2 0
3 0
4 0
4.25 0
4.5 0
5 10

Splined Interpolation 样条

样条过度可用于达到更现实的计时效果。由于动画通常用于模拟现实世界中发生的效果,因此您可能需要精确地控制对象的加速和减速,并且需要严格地对计时段进行操作,这时你就会用到样条关键帧。样条关键帧比起其他关键帧,多一个 KeySpline 属性,用于获取或设置用于定义此关键帧的动画进度的两个控制点。

若要了解 KeySpline 的工作原理,首先需要了解三次方贝塞尔曲线。一条三次方贝塞尔曲线由一个起点、一个终点和两个控制点来定义。

KeySpline 中的两个坐标定义这两个控制点。在描述关键样条时,贝塞尔曲线的起点始终为 0,终点始终为 1,这也就是只定义两个控制点的原因。所生成的曲线指定如何在一个时间段内内插动画;也就是说,该曲线表示该时间段内动画的目标属性的变化速率。

下面是来自MSDN的演示:

<SplineDoubleKeyFrame Value="500" 
  KeyTime="0:0:7" KeySpline="0.0,1.0 1.0,0.0" />
控制点为 (0.0, 1.0) 和 (1.0, 0.0) 的关键样条

Cc189038_JOLT_local_-624916683_graphicsmm_keyspline_0_1_1_0(zh-cn,VS_95)

上面的关键帧在开始时快速运动,再减速,然后再次加速,直到结束。

更多演示参看: http://msdn.microsoft.com/zh-cn/library/cc189038(VS.95).aspx 以及微软的演示 KeySpline 的例子,在这里可以看到:  运行此示例 

 

例子

下面我们先看一个简单例子:

<UserControl
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	x:Class="MySilverlight3Study_Animation2.MainPage"
	Width="640" Height="480">
	<Canvas>
    <Canvas.Resources>
        <Storyboard x:Name="myStoryboard">
            <!-- 总共10秒钟的动画 -->
            <DoubleAnimationUsingKeyFrames
       Storyboard.TargetName="MyAnimatedTranslateTransform"
       Storyboard.TargetProperty="X"
       Duration="0:0:10">
                <!-- 0到3秒内,平滑过渡到 500  -->
                <LinearDoubleKeyFrame Value="500" KeyTime="0:0:3" />

                <!-- 在第4秒时,突然过度到 400 -->
                <DiscreteDoubleKeyFrame Value="400" KeyTime="0:0:4" />

                <!-- 从第4秒开始,逐步加速,一直到第8秒 -->
                <SplineDoubleKeyFrame KeySpline="0.6,0.0 0.9,0.00" Value="0" KeyTime="0:0:8" />

   	        <!-- 第8秒到结束的第10秒,没有做任何事情  -->
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>
    </Canvas.Resources>

    <Rectangle MouseLeftButtonDown="Mouse_Clicked" Fill="BlueViolet"
 Width="50" Height="50">
        <Rectangle.RenderTransform>
            <TranslateTransform x:Name="MyAnimatedTranslateTransform" X="20" Y="20" />
        </Rectangle.RenderTransform>
    </Rectangle>
</Canvas>
</UserControl>

事件代码

private void Mouse_Clicked(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
	myStoryboard.Begin();
}

例子的演示效果如下,点击方块,开始动画:

 

代码说明:

我们对一个正方形的进行二维坐标平移来实现动画,动画是通过分帧的方式来定义实现的。

前3秒,平滑过渡,然后停下来,一直到第4秒,突然变化,然后加速运动。

LinearDoubleKeyFrame :  通过使用线性内插,可以在前一个关键帧的 Double 值及其自己的 Value 之间进行动画处理。

DiscreteDoubleKeyFrame  : 离散关键帧,在值之间产生突然"跳跃"(无内插算法)。换言之,已经过动画处理的属性在到达此关键帧的关键时间后才会更改,此时已经过动画处理的属性会突然转到目标值。

SplineDoubleKeyFrame : 通过 贝塞尔 曲线方式来定义动画变化节奏。详细看前面的介绍。

 

通过上面的代码,我们可以看到完成关键帧动画有以下3个步骤:

 

不同的属性类型有不同的动画类型。关键帧动画也是类似,如下是关键帧对应的分类。

属性类型 对应的关键帧动画类 支持的动画过渡方法
Color ColorAnimationUsingKeyFrames 离散、线性、样条
Double DoubleAnimationUsingKeyFrames 离散、线性、样条
Point PointAnimationUsingKeyFrames 离散、线性、样条
Object ObjectAnimationUsingKeyFrames 离散

ObjectAnimationUsingKeyFrames 很强大,我可以可以修改元素的任何属性,下面就是一个简单的例子:

例子使用了 ObjectAnimationUsingKeyFrames 对 Rectangle 的 Fill 属性进行动画处理。此动画按如下方式使用两个关键帧:

1.通过使用 DiscreteObjectKeyFrame,Rectangle 的 Fill 属性会在动画的前两秒之后突然更改为 LinearGradientBrush。

2.在动画的第三秒之后,Fill 属性会突然更改为另一个 LinearGradientBrush,然后一直保持到动画结束(总共四秒)。

<UserControl
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	x:Class="MySilverlight3Study_Animation2.MainPage"
	Width="120" Height="120">
<StackPanel>
	<StackPanel.Triggers>
	 <EventTrigger RoutedEvent="StackPanel.Loaded">
	 	<BeginStoryboard>
		<Storyboard x:Name="myStoryboard">

            <ObjectAnimationUsingKeyFrames
         Storyboard.TargetName="animatedRectangle"
         Storyboard.TargetProperty="Fill"
         Duration="0:0:4" RepeatBehavior="Forever">
                <ObjectAnimationUsingKeyFrames.KeyFrames>
		    <!-- 2秒时突变 //-->
                    <DiscreteObjectKeyFrame KeyTime="0:0:2">
                        <DiscreteObjectKeyFrame.Value>
                            <LinearGradientBrush>
                                <LinearGradientBrush.GradientStops>
                                    <GradientStop Color="Yellow" Offset="0.0" />
                                    <GradientStop Color="Orange" Offset="0.5" />
                                    <GradientStop Color="Red" Offset="1.0" />
                                </LinearGradientBrush.GradientStops>
                            </LinearGradientBrush>
                        </DiscreteObjectKeyFrame.Value>
                    </DiscreteObjectKeyFrame>

                    <!-- 3秒时再次突变 -->
                    <DiscreteObjectKeyFrame KeyTime="0:0:3">
                        <DiscreteObjectKeyFrame.Value>
                            <RadialGradientBrush GradientOrigin="0.75,0.25">
                                <RadialGradientBrush.GradientStops>
                                    <GradientStop Color="White" Offset="0.0" />
                                    <GradientStop Color="MediumBlue" Offset="0.5" />
                                    <GradientStop Color="Black" Offset="1.0" />
                                </RadialGradientBrush.GradientStops>
                            </RadialGradientBrush>
                        </DiscreteObjectKeyFrame.Value>
                    </DiscreteObjectKeyFrame>

                </ObjectAnimationUsingKeyFrames.KeyFrames>
            </ObjectAnimationUsingKeyFrames>
        </Storyboard>
		</BeginStoryboard>
        </EventTrigger>
	</StackPanel.Triggers>
    <!-- 我们将对这个正方形的 Fill 属性来做动画. -->
    <Rectangle x:Name="animatedRectangle" Width="100" Height="100" Fill="Aqua" Margin="10" />
</StackPanel>
</UserControl>

执行效果如下:

 

 

参考资料:

Animations
http://silverlight.net/learn/quickstarts/animations/

Silverlight 使用 XAML 和 Expression Blend 创建动画
http://msdn.microsoft.com/zh-cn/magazine/cc721608.aspx

关键帧动画
http://msdn.microsoft.com/zh-cn/library/cc189038(VS.95).aspx

稳扎稳打Silverlight(11) - 2.0动画之ColorAnimation, DoubleAnimation, PointAnimation, 内插关键帧动画
http://www.cnblogs.com/webabcd/archive/2008/11/06/1327758.html

使用 XAML 和 Expression Blend 创建动画
http://msdn.microsoft.com/zh-cn/magazine/cc721608.aspx

ObjectAnimationUsingKeyFrames 类
http://msdn.microsoft.com/zh-cn/library/system.windows.media.animation.objectanimationusingkeyframes(VS.95).aspx

posted on 2009-12-22 16:56:07 by ghj1976  评论(0) 阅读(1888)

Silverlight学习笔记--文字对象

文本的处理

TextBlock 是 Silverlight 中的一个常用又有用的控件。我们可以通过TextBlock呈现只读的文本。

下面是演示代码

<UserControl
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	x:Class="SilverlightStudy.MainPage"
	Width="640" Height="480">
  <TextBlock FontFamily="Arial Black" FontSize="16"
    Foreground="Red" Width="500">
	欢迎
         <Run FontSize="34" FontStyle="Italic" Foreground="Blue"></Run>
        <Run FontSize="22" FontStretch="ExtraCondensed">来到</Run>
        <Run>这里!</Run>
	<LineBreak />
	<Bold>哈哈哈哈</Bold>
	<Italic>我是谁?</Italic>
	<Underline>太阳出来了</Underline>
	<LineBreak />
  </TextBlock>
</UserControl>

演示效果:

image

其中一些属性如下:

FontFamily: Silverlight内置了十几种常见拉丁字体,如Arial,Comic Sans MS,Courier New,Lucida Sans Unicode等。默认使用的字体是 Portable User Interface。这是一种复合字体,它使用若干字体来实现 Silverlight 所支持的一组国际语言。这些字体包括针对许多西方书写系统的"Lucida Sans Unicode"和"Lucida Grande",以及针对东亚书写系统的更多字体。Silverlight 会根据文字的语言选择最佳的字体。

如果您指定的 FontFamily 不存在,即使它是唯一可用的字体系列值,Silverlight 仍将为 Portable User Interface 值提供备用值以用于呈现。

上面例子中,我把字体设置成 Arial Black,由于其中的中文无法找到对应字体,就使用了 Portable User Interface  来显示的。由于是中文,上述文字就是用宋体的样式来显示的。

如果我们直接把字体修改为其他中文字体,比如: 微软雅黑, 程序就会报警告:

The font, 微软雅黑, is not a built-in Silverlight font and will not be displayed to users who run your Silverlight application.  To display the font, either install the font on your computer and then use Expression Blend to embed the font in your project, or add the font files to your project.   

如何解决这个问题以及关于字体的更多信息,你可以看下面几篇文章: 
文本和字体: http://msdn.microsoft.com/zh-cn/library/cc189010(VS.95).aspx 

解决Silverlight引用中文字体的问题

http://blog.joycode.com/joy/archive/2007/05/28/103441.aspx

Silverlight Tip of the Day #46 – Font Support in Silverlight

FontSize:指定所需字体大小(以像素为单位)。值必须为非负数。 默认值为 11 像素。

FontStretch: 指定所需的字体标志符号宽度。

默认值为 Normal。FontStretch 的效果依赖于正使用的特定字体系列,并且只能指定字体系列中已经存在的字体。该属性不会导致以编程方式拉伸标志符号。(注意:如果 FontStretch 映射不可用,您可以考虑将某一变换应用于文本。)

压缩或者拉长的比率请参看下面文档

http://msdn.microsoft.com/zh-cn/library/system.windows.fontstretches(VS.95).aspx

FontStyle: 指定所需字形为普通还是斜体。
可设置两种值: Normal, Italic(斜体)。默认值为 Normal。FontWeight 的效果依赖于正使用的特定字体系列,并且通常只能指定字体系列中已经存在的字体。Silverlight 不以编程方式创建修剪变形来模拟斜体。

FontWeight: 指定所需的字体标志符号粗细。即:文字的胖瘦。可设置为Thin, ExtraLight, Light, Normal, Medium, SemiBold, Bold, ExtraBold, Black, ExtraBlack.这些值是否起作用还要取决于你所选择的字体。默认值为 Normal。

FontWeight 的效果依赖于正使用的特定字体系列,并且通常只能指定字体系列中已经存在的字体。修剪不会以编程方式创建备用粗细值,除非字体系列中包含普通粗细字体,而不包含粗体字体。在这种情况下,Silverlight 将通过增加使用二维图形算法的笔画宽度来模拟粗体字体。

TextDecorations: 对文字的修饰,默认设置为无修饰。若要指定下划线修饰,请将 TextDecorations 属性设置为 Underline。

Foreground:  通过这个属性可以设置文字的前景色填充。不但可以使用颜色值,还可以通过设置solid color, gradient, image 及 video笔刷进行填充。

比如下面代码就是使用的图片做的文字前景刷子

<TextBlock Text="SHRUBBERY">
  <TextBlock.Foreground>
    <ImageBrush ImageSource="forest.jpg"/>
  </TextBlock.Foreground>
</TextBlock>

执行效果:

image

Run:   你可以在TextBlock中使用Run标签创建内联元素,每个Run都可以设置上面提到的属性。这样一篇文档,就可以每处显示的风格都不一样。

 

参考资料:

了解Silverlight提供的TextBlock(文字区块)元素对象
http://silverlight.cn/node/356

[Silverlight]TextBlock控件全攻略
http://www.cnblogs.com/024hi/archive/2008/12/04/1347337.html

文本和字体
http://msdn.microsoft.com/zh-cn/library/cc189010(VS.95).aspx

WPF4数据绑定应用之创建具有多种显示效果的字串
http://www.cnblogs.com/bitfan/archive/2009/11/12/1601857.html

posted on 2009-12-04 14:08:23 by ghj1976  评论(0) 阅读(2269)

Silverlight学习笔记--绘制与着色(下)

下面是刷子的一些内容:

纯色刷子(SolidColorBrush)

Silverlight中使用纯色刷子可以有多种方式如下,

<object property="predefinedColor"/>
- or -
<object property="#rgb"/>
- or -
<object property="#argb"/>
- or -
<object property="#rrggbb"/>
- or -
<object property="#aarrggbb"/>
- or -
<object property="sc# scA,scR,scG,scB"/>

分别代表的意思如下:

predefinedColor   Colors 类预定义的颜色之一。

rgb     一个三位数的十六进制数字。第一位数指定颜色的 R 值,第二位数指定 G 值,第三位数指定 B 值。例如 00F。

argb   一个四位数的十六进制数字。第一位数指定颜色的 A 值,第二位数指定其 R 值,下一位数指定 G 值,最后一位数指定其 B 值。例如 F00F。

rrggbb   一个六位数的十六进制数字。前两位数指定颜色的 R 值,下两位数指定其 G 值,最后两位数指定其 B 值。例如 0000FF。

aarrggbb   一个八位数的十六进制数字。前两位数指定颜色的 A 值,下两位数指定其 R 值,接下来的两位指定其 G 值,最后两位数指定其 B 值。例如 FF0000FF。

scA   System.Single   颜色的 ScA 值。

scR   System.Single   颜色的 ScR 值。

scG   System.Single   颜色的 ScG 值。

scB   System.Single   颜色的 ScB 值。

演示代码如下:

<UserControl
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	x:Class="SilverlightStudy.MainPage"
	Width="640" Height="480">
<Canvas>
  <Ellipse Height="90" Width="90" Canvas.Left="10" Canvas.Top="10" Fill="black"/>

  <Ellipse Height="90" Width="90" Canvas.Left="110" Canvas.Top="10" Fill="#000000"/>

  <Ellipse Height="90" Width="90" Canvas.Left="210" Canvas.Top="10" Fill="#000" />

  <Ellipse Height="90" Width="90" Canvas.Left="310" Canvas.Top="10" Fill="sc# 0.0 0.0 1.0" />

  <Ellipse Height="90" Width="90" Canvas.Left="10" Canvas.Top="110" Fill="#ff000000"/>

  <Ellipse Height="90" Width="90" Canvas.Left="110" Canvas.Top="110">
    <Ellipse.Fill>
	  <SolidColorBrush Color="Black"/>
    </Ellipse.Fill>
  </Ellipse>
 
  <Ellipse Height="90" Width="90" Canvas.Left="210" Canvas.Top="110" Fill="#f000"/>
 
  </Canvas>
</UserControl>

演示效果如下:

image

需要注明的是 WPF 中支持的另外一种颜色定义方式,如下,Silverlight 是不支持的:

<!-- This rectangle fill uses the sRGB color profile and values to create a complete opaque blue. -->
  <Rectangle Width="50" Height="50"  Margin="10">
    <Rectangle.Fill>
      <SolidColorBrush Color="ContextColor 
	   file://C:/WINDOWS/system32/spool/drivers/color/sRGB%20Color%20Space%20Profile.icm
	   1.0,0.0,0.0,1.0"/>
    </Rectangle.Fill>
  </Rectangle>

线性渐变刷子(LinearGradientBrush)

默认的线性渐变是沿对角方向进行的。默认情况下,线性渐变的 StartPoint 是被绘制区域的左上角 (0,0),其 EndPoint 是被绘制区域的右下角 (1,1)。所得渐变的颜色是沿着对角方向路径插入的。如下图显示了对角方向的渐变。图中添加了一条线,用于突出显示渐变从起点到终点的插值路径。

对角线方向线性渐变的渐变轴

 

具有突出显示的渐变停止点的对角线性渐变,如下图:

线性渐变中的渐变停止点

演示代码

<UserControl
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	x:Class="SilverlightStudy.MainPage"
	Width="640" Height="480">
<Canvas>

  <!-- 水平渐变 //-->
  <Rectangle Width="140" Height="70" Canvas.Left="155" Canvas.Top="10">
    <Rectangle.Fill>
      <LinearGradientBrush  StartPoint="0,0" EndPoint="1,0">
        <GradientStop Color="Red" Offset="0.0" />
        <GradientStop Color="LimeGreen" Offset="1.0" />
      </LinearGradientBrush>
    </Rectangle.Fill>
  </Rectangle>
  <!-- 垂直渐变 //-->
 <Rectangle Width="140" Height="70" Canvas.Left="300" Canvas.Top="10">
    <Rectangle.Fill>
      <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
        <GradientStop Color="Blue" Offset="0.0" />
        <GradientStop Color="LimeGreen" Offset="1.0" />
      </LinearGradientBrush>
    </Rectangle.Fill>
  </Rectangle>
  
  <!-- 具有突出显示的渐变停止点的对角线性渐变 //-->
 <Rectangle Width="140" Height="70" Canvas.Left="450" Canvas.Top="10">
    <Rectangle.Fill>
      <LinearGradientBrush>
        <GradientStop Color="Yellow" Offset="0.0" />
        <GradientStop Color="Red" Offset="0.25" />
        <GradientStop Color="Blue" Offset="0.75" />
        <GradientStop Color="LimeGreen" Offset="1.0" />
      </LinearGradientBrush>
    </Rectangle.Fill>
  </Rectangle>
  
  </Canvas>
</UserControl>

执行效果

image

其中的一些属性说明

Offset 渐变停止点在渐变向量中的位置。值 0.0 指定停止点位于渐变向量的开始处;而值 1.0 指定停止点位于渐变向量的末尾处。如果没有设置这个值,则默认是0.0。

 

径向渐变刷子(RadialGradientBrush)

焦点定义渐变的开始,而圆定义渐变的终点。

范例代码:

<!-- This rectangle is painted with a diagonal linear gradient. -->
<Rectangle Width="200" Height="100">
  <Rectangle.Fill>
    <RadialGradientBrush 
      GradientOrigin="0.5,0.5" Center="0.5,0.5" 
      RadiusX="0.5" RadiusY="0.5">
      <GradientStop Color="Yellow" Offset="0" />
      <GradientStop Color="Red" Offset="0.25" />
      <GradientStop Color="Blue" Offset="0.75" />
      <GradientStop Color="LimeGreen" Offset="1" />
    </RadialGradientBrush>
  </Rectangle.Fill>
</Rectangle>
效果图如下:

径向渐变中的渐变停止点

其中一些属性的意思如下

GradientOrigin : 定义渐变开始的二维焦点的位置。(下面演示图中的红点),可以在径向渐变最外面的圆外面,渐变的二维焦点的位置。默认值为 (0.5, 0.5)。

Center :径向渐变最外面的圆的圆心,渐变圆的默认中心点位置是 (0.5, 0.5)。

RadiusX:径向渐变最外面的圆的水平半径,默认值为 0.5。

RadiusY:径向渐变最外面的圆的垂直半径,默认值为 0.5。

注意,上面坐标系是相对于边界框的:0 表示边界框的 0%,1 表示边界框的 100%。可以通过将 MappingMode 属性设置为值 Absolute 来更改此坐标系。绝对坐标系不是相对于边界框的。值直接在本地坐标系中解释。

我们可以看下面的例子来理解具有不同 GradientOrigin、Center、RadiusX 和 RadiusY 设置的 RadialGradientBrush。

RadialGradientBrush 设置

 

图像绘制刷子(ImageBrush)

实例代码:

<UserControl
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	x:Class="SilverlightStudy.MainPage"
	Width="640" Height="480">
<Canvas>
  <Rectangle Height="180" Width="90" Canvas.Left="110" Canvas.Top="36"
      Stroke="Bisque" StrokeThickness="1">
    <Rectangle.Fill>
      <ImageBrush ImageSource="7116_2004321149418456.jpg" Stretch="Uniform"/>
    </Rectangle.Fill>
  </Rectangle>
  </Canvas>
</UserControl>

效果如下:这里的原始图片是一个380*486 的大尺寸图片。

image

 

其中的 Stretch 属性用于控制图像的拉伸、对齐和平铺方式。默认值为 Fill。

Stretch 属性可以设置为以下几种值:

下面的图像阐释了不同的 Stretch 设置。

image

 

参考资料:

Color 结构
http://msdn.microsoft.com/zh-cn/library/system.windows.media.color.aspx

LinearGradientBrush 类
http://msdn.microsoft.com/zh-cn/library/system.windows.media.lineargradientbrush.aspx

使用纯色和渐变进行绘制概述
http://msdn.microsoft.com/zh-cn/library/ms754083.aspx

posted on 2009-11-25 17:03:09 by ghj1976  评论(1) 阅读(2165)

Silverlight学习笔记--绘制与着色(上)

最近通过看WebCase的录像来学习Silverlight,为了避免学了后面忘了前面,把录像中的重点整理成笔记记录下来。

通过录像来学习Silverlight,我推荐看苏鹏讲的Silverlight探秘系列课程,这个系列课程已经讲到50多讲了。由浅入深,而且连绵不断,确实很有帮助。

 

这篇博客是对 苏鹏讲解的“Silverlight探秘系列课程(3):绘制与着色”的笔记,网上有很多地方都有这个课程下载,我就不给链接地址了。不过推荐使用 iReaper 来下载讲座视频。

 

椭圆

<Ellipse
    Height="200" Width="200"
    Stroke="Black" StrokeThickness="10" Fill="SlateBlue"  />

image

相对于父控件的定位可以有下面2种:

情况1:

<UserControl
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	x:Class="SilverlightStudy.MainPage"
	Width="640" Height="480">
<Ellipse 
      Height="200" Width="250"
      Stroke="Black" StrokeThickness="10" Fill="SlateBlue" 
	  HorizontalAlignment="Left" VerticalAlignment="Top" Margin="10,12,0,0" />
</UserControl>

情况2:

<UserControl
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	x:Class="SilverlightStudy.MainPage"
	Width="640" Height="480">
<Canvas xmlns="http://schemas.microsoft.com/client/2007" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">	
<Ellipse 
      Height="200" Width="250"
      Stroke="Black" StrokeThickness="10" Fill="SlateBlue" 
	  Canvas.Left="50" Canvas.Top="30" />
</Canvas>
</UserControl>


图像的遮挡
如果没有指定ZIndex, 则后画的遮挡了先画的;如果指定了ZIndex :则给定 element 的 value 越大,element 在前景中出现的可能性就越大。同样,如果 element 具有一个相对较低的 value,则 element 将可能出现在背景中。例如,具有 value 为 5 的 element 将出现在具有 value 为 4 的 element 的上方,后者又将出现在具有值为 3 的 element 的上方,依此类推。允许负值,并且这些负值也适用此优先级模式。 如下图,

 

<UserControl
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	x:Class="SilverlightStudy.MainPage"
	Width="640" Height="480">
<Canvas >	
<Ellipse
      Canvas.ZIndex="3"
      Canvas.Left="5" Canvas.Top="5"
      Height="200" Width="200"
      Stroke="Black" StrokeThickness="10" Fill="Silver" />

  <Ellipse
      Canvas.ZIndex="2"
      Canvas.Left="50" Canvas.Top="50"
      Height="200" Width="200"
      Stroke="Black" StrokeThickness="10" Fill="DeepSkyBlue" />

  <Ellipse
      Canvas.ZIndex="-1"
      Canvas.Left="95" Canvas.Top="95"
      Height="200" Width="200"
      Stroke="Black" StrokeThickness="10" Fill="Lime" />
</Canvas>
</UserControl>
效果图如下:

image

线条

<Line X1="280" Y1="10" X2="10" Y2="280" Stroke="Black" StrokeThickness="5"/>

使用 Line 元素的 X1 和 Y1 属性设置线条起点,并使用 Line 元素的 X2 和 Y2 属性来设置线条终点。最后,设置 Line 元素的 Stroke 和 StrokeThickness,因为没有笔画的线条是看不见的。为线条设置 Fill 元素将毫无意义,因为线条没有内部区域。

矩形

 <Rectangle
    Width="200"
    Height="100"
    Fill="Blue"
    Stroke="Black" StrokeThickness="4"
    RadiusX="20" RadiusY="20"/>

image

若要绘制矩形圆角,请指定可选的 RadiusX 和 RadiusY 属性。RadiusX 和 RadiusY 属性设置用于使矩形的角变圆的椭圆的 x 轴和 y 轴半径。这两个的默认值为0,即,没有圆角。

封闭多边形

<Polygon Points="10,10 10,110 110,110 110,85 45,10"
      Stroke="Black" StrokeThickness="10" Fill="LightBlue"/>

image

注意,在可扩展应用程序标记语言 (XAML) 中,我们使用由逗号分隔的 x 和 y 坐标对组成的空格分隔列表来设置 Points 属性。即使用简单表示法, x1,y1 x2,y2 ... xn,yn。

未封闭多边形

我们还是使用上面的点,注意,这时候 Fill 意义不大,我们就没设置,这个值也是可设置的

<Polyline Points="10,10 10,110 110,110 110,85 45,10"
      Stroke="Black" StrokeThickness="10" />

效果如下:

image

增加 Fill="LightBlue" 带来的效果如下:

image

 

路径

<UserControl
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	x:Class="SilverlightStudy.MainPage"
	Width="640" Height="480">
<Canvas>
	<Path Data="M0,0 L11.5,0 11.5,30 5.75,40 0,30z"
      Stroke="Black" Fill="SlateBlue" Canvas.Left="118" Canvas.Top="57" 
	  UseLayoutRounding="False" />
	  
	<Path Data="M 10,100 C 10,300 300,-200 250,100z"
      Stroke="Red" Fill="Orange" Canvas.Left="54" Canvas.Top="167" 
	  UseLayoutRounding="False" />

        <Path Data="M 0,200 L100,200 50,50z"
      Stroke="Black" Fill="Gray" Canvas.Left="397" Canvas.Top="66" 
	  UseLayoutRounding="False" />
</Canvas>
</UserControl>

image

上面 Path 元素的 Data 属性描述的是路径,这里的路径描述使用几何迷你语言命令,这个语言命令规范如下图:

image

参考资料:

WPF 中的形状和基本绘图概述
http://msdn.microsoft.com/zh-cn/library/ms747393.aspx

posted on 2009-11-24 17:22:59 by ghj1976  评论(1) 阅读(2302)

WPF,Silverlight 中的 xmlns,xmlns:x(2)

前一篇文章 “WPF,Silverlight 中的 xmlns,xmlns:x”  中提到了: 目前对于大多数的 WPF 应用程序以及 SDK 的 WPF 部分中给出的几乎所有示例版本的WPF,Silverlight 2.0 (含)以后的开发工具, 默认的 xmlns 命名空间均映射到 WPF 命名空间 http://schemas.microsoft.com/winfx/2006/xaml/presentation

对于Silverlight来说,从 Silverlight 2 (含)以及更高版本的 Silverlight 开始,大多数工具都默认使用 http://schemas.microsoft.com/winfx/2006/xaml/presentation 命名空间来生成 Silverlight 的 XAML 文件。不过,Silverlight 仍然支持 http://schemas.microsoft.com/client/2007  XAML 命名空间(这是用于 Silverlight 1.0 的 XAML 命名空间)。

 

比起WPF,Silverlight 对设置 xmlns 值加了以下限制:

 

比起WPF,Silverlight 对映射 xmlns 值的程序集和命名空间加了以下限制:

 

参考资料:

Silverlight 和 WPF 之间的 XAML 处理差异
http://msdn.microsoft.com/zh-cn/library/cc917841(VS.95).aspx (中文)

http://msdn.microsoft.com/en-us/library/cc917841(VS.95).aspx (英文)

posted on 2009-11-23 16:32:40 by ghj1976  评论(0) 阅读(2452)

WPF,Silverlight 中的 xmlns,xmlns:x

我们在每一个XAML文件中都可以看到下面的信息:

Silverlight应用
<
UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" > </UserControl>
WPF应用
<
Window x:Class="WpfApplication1.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="300"> <Grid> </Grid> </Window>

      XAML文件首先是一个XML文件。为了验证自己和子元素的合法性,即保证在XML文档中的元素和属性名字的合法性,XML规范了XML命名空间,参看下面文档:

http://www.opendl.com/openxml/w3/TR/xml-names/xml-names-gb.html

      上面例子中,xmlns 属性专门指默认的 xmlns 命名空间。在默认的 xmlns 命名空间中,可以不使用前缀指定标记中的对象元素。目前对于大多数的 WPF 应用程序以及 SDK 的 WPF 部分中给出的几乎所有示例版本的WPF,Silverlight 2.0 (含)以后的开发工具, 默认的 xmlns 命名空间均映射到 WPF 命名空间 http://schemas.microsoft.com/winfx/2006/xaml/presentation

      xmlns:x 属性指示另外一个 xmlns 命名空间,该命名空间映射 XAML 语言命名空间 http://schemas.microsoft.com/winfx/2006/xaml 。在具有此映射的文件的标记中引用时,XAML 规范定义的所需语言组件带有 x: 前缀。

如下图所示:

<Page 根元素的开始对象元素
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 默认 (WPF) 命名空间
就类似于如下的C#代码:
using System.Windows;
using System.Windows.Automation 
using System.Windows.Controls;
using System.Windows.Controls.Primitives 
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Forms.Integration 
using System.Windows.Ink 
using System.Windows.Media.Animation 
using System.Windows.Media.Effects 
using System.Windows.Media.Media3D 
using System.Windows.Media.TextFormatting 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 这是XAML语言命名空间,用于映射System.Windows.Markup命名空间中的类型,而且它也定义了XAML编译器或解析器中的一些特殊的指令。这些指令通常是作为XML元素的特性出现的,因此它们看上去像宿主元素的属性,但实际上并不是如此。
x:Class="MyNamespace.MyPageCode" 分部类声明,它将标记连接到此分部类中定义的任何代码隐藏
> 根的对象元素的末尾,但由于页面包含子元素,因此尚未结束

 

参考资料:

WPF学习笔记1:XAML之NameSpace
http://www.cnblogs.com/jacksonyin/archive/2008/02/25/1080336.html

HTML xmlns 属性
http://www.w3school.com.cn/tags/tag_prop_xmlns.asp

XAML 概述
http://msdn.microsoft.com/zh-cn/library/ms752059.aspx

《WPF揭秘》 2.3  命名空间
http://book.csdn.net/bookfiles/677/10067721293.shtml

posted on 2009-11-23 14:06:35 by ghj1976  评论(1) 阅读(2684)

sRGB和scRGB的区别

.net FrameWork 3.0 后,我们会发现有两个Color数据结构。
一个是:System.Drawing.Color
一个是:System.Windows.Media.Color

这两个结构有啥区别呢?

下面是对这两个类的属性的一个简单比较:

  System.Drawing.Color Structure System.Windows.Media.Color Structure
所在组件 System.Drawing.dll PresentationCore.dll
支持的版本

.NET Framework
Supported in: 3.5, 3.0 SP1, 3.0, 2.0 SP1, 2.0, 1.1, 1.0

.NET Compact Framework
Supported in: 3.5, 2.0, 1.0

XNA Framework
Supported in: 1.0

.NET Framework
Supported in: 3.5, 3.0 SP1, 3.0

A Gets the alpha component value of this Color structure. Gets or sets the sRGB alpha channel value of the color.
B Gets the blue component value of this Color structure. Gets or sets the sRGB blue channel value of the color.
G Gets the green component value of this Color structure. Gets or sets the sRGB green channel value of the color.
R Gets the red component value of this Color structure. Gets or sets the sRGB red channel value of the color.
ScA 不支持 Gets or sets the ScRGB alpha channel value of the color.
ScB 不支持 Gets or sets the ScRGB blue channel value of the color.
ScG 不支持 Gets or sets the ScRGB green channel value of the color.
ScR 不支持 Gets or sets the ScRGB red channel value of the color.
获得系统支持的一些颜色 在Color中定义了141种系统预定义的颜色
调用方法如下:
System.Drawing.Color.AliceBlue
不在Color中定义,而是Colors中定义,获得方法类似下面写法:
System.Windows.Media.Colors.AliceBlue
系统一共预定义了141个颜色。
小结 只支持 sRGB。向下兼容 同时支持 sRGB、ScRGB。不兼容3.0以下的版本

我们可以在上面看到,关键是sRGB和ScRGB两种颜色表示方法。这两种有啥差别呢?我们来看下面三副图,先来感性的看看:

人眼可以看到的颜色范围以及sRGB的范围

这幅图的巧妙之外在于它通过“归一化”,用两维平面来表示三个数据。X轴是红色的比例,Y轴是绿色的比例,而Z轴是蓝色的比例,虽然Z轴没有画出来,但它的比例数据可以很方便地计算出来。比方红是0.2,绿是0.3,那么蓝就是0.5。因为它们三者加起来必须等于1,不然怎么叫“归一化”呢!图上任何一点的蓝色分量,你都可以用这个方法计算出来。

图中的“舌形”色域空间,是人眼能够辨别的色彩空间,它的边缘围绕一道从波长从380到700(毫微米)的光谱,中间就是用红、绿、蓝三种颜色按不同比例调配出来的颜色。

而图中的三角的区域,是 sRGB 可以表示的颜色范围。显然有一些我们人类可以看到的颜色,但是sRGB来描述的。

scRGB的颜色范围和人眼可以看到的范围

上面这幅图对比了 sRGB、人眼、ScRGB 可以表示的颜色范围。

sRGB和scRGB图的区别

上面这幅图是sRGB和ScRGB两幅图的比较,注意看放大了的云彩。

sRGB 和 scRGB 的转换 

在 System.Windows.Media.Color 结构中,scRGB原色其实是被储存成单精度(single-precision)的浮点数。想要容纳scRGB颜色空间,Color 结构包含四个主要的property,类型都是float,分别为ScA、ScR、ScG、ScB。
这些property和A、R、G、B property 会相互影响,改编G property也会造成ScG property的改变,反之亦然。

当G property 为0,ScG property 也会为0;当G property 为255,ScG property 就会为1。在这个范围之内,
关系并非是线性的,如下表所示。

scG G
<= 0 0
0.1 89
0.2 124
0.3 149
0.4 170
0.5 188
0.6 203
0.7 218
0.8 231
0.9 243
>=1.0 255

ScR 与 R 之间的关系,ScB与B之间的关系,以及ScG与G之间的关系,也都是一样的。ScG的值可以小于0或者大于1,以容纳超出显示器和sRGB数字范围的颜色。

sRGB和scRGB的比较

sRGB目标是使同一网页在不同计算机上显示时的色彩更一致,但只适用于CRT显示器。微软HD Photo项目负责人克劳说,sRGB的挑战在于它只是完整色彩空间的一个子集,当使用sRGB编码时,我们会丢掉一些色彩。

scRGB色彩空间是sRGB扩展,对于黑色和纯绿色而言,这二者没有任何分别。二者的差别就在于scRGB能够显示人眼无法分辨的颜色,其精细程度也超过了sRGB。

scRGB描述每个点所需要的位数是sRGB 2倍,甚至是4倍。不仅能够使用整数,还能够使用浮点数,提高图像的精细程度。

参考资料:

关于scRGB色彩空间
http://hi.baidu.com/cybo/blog/item/8f24ba38bbb584c1d5622597.html

第二章 基本的Brush画刷类 [App = Code + Markup]
http://www.cnblogs.com/rickiedu/archive/2007/04/04/699529.html

GDI+与WPF中的颜色简析
http://blog.csdn.net/johnsuna/archive/2007/08/27/1761061.aspx

简述WPF中的图像像素格式(PixelFormats)
http://blog.csdn.net/johnsuna/archive/2007/08/28/1762901.aspx

posted on 2007-12-30 14:11:00 by ghj1976  评论(3) 阅读(5949)

推荐阅读《Applications = Code + Markup》

        最近在通过一边动手做一个智能客户端的WPF应用,一边在学习WPF技术。

        WPF技术跟之前的Windows Form应用两者给我的感觉是:这两个技术是一个非常大的跨越。很多Windows Form的心得,想法,思想在WPF中都不再有用了。

        我最近几年学习新技术,很多时候是通过网上看文章,自己查MSDN,或者看杂志的文章来完成学习的,而不是看图书。因为我之前很多的经验心得帮助我很容易的完成学习。

        在一边学习WPF,一边自己开发智能客户端的程序时候,我发现我很多开发界面的想法是基于Windows Form的思想。即:通过Windows Form 的思想,想到这里需要有一个啥样的控件,然后再去WPF中去找如何实现这样的需求。你看我这个系列的博客,就可以看到我的这个学习历程。
http://blog.joycode.com/ghj/category/1428.aspx

        但是我觉得设计一个WPF程序的界面,不应该用Windows Form程序的思想,而是应该用 WPF程序的思想。但是你让我说出,啥是WPF程序的思想,我又很难表述。

        我之前那种学习方法,看MSDN,看杂志文章。这种不是系列的,循序渐进的学习方法,我觉得让我无法掌握WPF的思想,要想掌握WPF的思想,需要一个系列的学习。

        幸运的是,我拿到的一本Charles Petzold出的《Applications = Code + Markup》。我觉得这本书对我学习WPF有以下帮助:

        首先,这是一本循序渐进的书。尤其是他的代码例子,非常简洁的代码,而且一层层的深入。简练有效,通俗易懂。代码写的简练并不难,难的是这是他在讲一个比较深入问题的时候,写的代码也是简练的。深入讲解一个问题时候,使用简洁的代码,对学习者的帮助不言而喻。

         这本书可不是21天学会***那类的书,只是一个简单入门的书。这本书有1000页。厚厚的一本,这本书的定位是:
Developer Reference
Expert coverage of core topics
Extensive ,pragmatic coding examples
Builds professional-level proficiency with a Microsoft technology
能用简洁的代码描述清楚复杂的问题,非常难得的一本书。

        说实话,我的英语词汇量并不足,但是这本书我还是能比较通顺的读下来。甚至比阅读部分英文的资料文章还要容易。可见本文的通俗易懂性。

其他WPF的技术图书我没有看过,但是我看过的这本英文原版的《Applications = Code + Markup》确实值得阅读,和作为一本开发资料时常查阅。

Applications = Code + Markup 


参考资料:

Applications = Code + Markup: A Guide to the Microsoft Windows Presentation Foundation
http://www.amazon.com/Applications-Code-Markup-Presentation-Foundation/dp/0735619573/sr=8-1/qid=1164814449/ref=pd_bbs_1/104-6804148-3392750?ie=UTF8&s=books

CSDN上的电子版下载地址:Microsoft Press: Applications=Code+Markup Sep2006 INTERNAL eBook-BBL

思归对这本书的评价
http://blog.joycode.com/saucer/archive/2006/09/01/82430.aspx

On Petzold's Applications = Code + Markup

这本书应该会被电子工业出版社翻译出版的, 下面这篇博客就在征求同译者 http://www.cnblogs.com/sheva/archive/2006/08/17/479818.html

posted on 2007-10-07 14:52:00 by ghj1976  评论(7) 阅读(6032)

WPF中展开一个TreeView控件的所有树节点

       在 Windows Form 应用中,我们碰到需要展开一个TreeView 控件的所有树节点的时候很简单,微软已经替我们提供了ExpandAll 方法,我们只要简单的一行代码tv_QTree.ExpandAll();就可以了。即 System.Windows.Forms 命名空间的 TreeView.ExpandAll 方法 。

       在WPF中,我们会发现,System.Windows.Controls.TreeView 中没有了 ExpandAll 方法。唯一跟展开有关系的属性和方法就是每一个TreeViewItem 中有一个属性IsExpanded 属性。这个属性定义这个节点是否打开。MSDN帮助如下:

       Gets or sets whether the nested items in a TreeViewItem are expanded or collapsed. This is a dependency property.

       这时候如何办呢? 很简单,自己写个递归,遍历这个树的每一个子节点,然后把每一个子节点的 IsExpanded 设置为 true.

       你可以通过以下几个链接看到这个解决方案:

       http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=976861&SiteID=1

       http://shevaspace.spaces.live.com/blog/cns!FD9A0F1F8DD06954!463.entry

       http://blogs.msdn.com/okoboji/archive/2006/09/20/764019.aspx

 

       我们可以在上面解决方案基础上进一步发展。

       用扩展方法来给 System.Windows.Controls.TreeView 类扩展个 ExpandAll方法方法。有关扩展方法的一些基础知识可以参看我之前的博客:C#3.0 中的扩展方法 (Extension Methods)

      我的扩展方法代码如下:

/// <summary>
/// 郭红俊的扩展方法
/// </summary>
public static class ExtensionMethods
{
    /// <summary>
    ///
    /// </summary>
    /// <param name="treeView"></param>
    public static void ExpandAll(this System.Windows.Controls.TreeView treeView)
    {
        ExpandInternal(treeView);
    }

    /// <summary>
    ///
    /// </summary>
    /// <param name="targetItemContainer"></param>
    private static void ExpandInternal(System.Windows.Controls.ItemsControl targetItemContainer)
    {
        if (targetItemContainer == null) return;
        if (targetItemContainer.Items == null) return;
        for (int i = 0; i < targetItemContainer.Items.Count; i++)
        {
            System.Windows.Controls.TreeViewItem treeItem = targetItemContainer.Items[i] as System.Windows.Controls.TreeViewItem;
            if (treeItem == null) continue;
            if (!treeItem.HasItems) continue;

            treeItem.IsExpanded = true;
            ExpandInternal(treeItem);
        }

    }

}

 

扩展方法的使用方法也请参看C#3.0 中的扩展方法 (Extension Methods) 提到的注意事项。

posted on 2007-09-05 16:29:00 by ghj1976  评论(6) 阅读(6078)

GridSplitter 的 ResizeBehavior 属性介绍

我们先来看一个我们在使用 GridSplitter 时,经常可能会碰到的问题:

把一个窗体分成2部分,这两部分中间是一个GridSplitter来支持这左右两部分的宽度变动。类似下面的效果图:

GridSplitter 的 ResizeBehavior 属性介绍01

中间红色就是分割线,这个分割线支持左右两部分的宽度变更,一般我们会把这个需求写成类似下面XAML文件的方式:

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="WpfApplication_GridSplitter.Window1"
    Title="Window1" Height="100" Width="300">
    <Grid Width="Auto" Height="Auto" >
        <Grid.ColumnDefinitions >
            <ColumnDefinition Width="*"  />
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="5*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions />
        <StackPanel Grid.Column="0"  Background="DarkBlue" />
        <GridSplitter Grid.Column="1"  Width="3" Background="Red" />
        <StackPanel Grid.Column="2"  Background="#FFAEA130" />
    </Grid>
</Window>

但是仅仅上面的代码,我们在拖动分割线的时候,会发现,分割线右边的尺寸发生变化了,而左边的尺寸没有发生变化,类似下面效果图:

GridSplitter 的 ResizeBehavior 属性介绍02

中间出现了一个空白区域。

这是为何呢??

原因很简单, GridSplitter 默认的 ResizeBehavior 属性为:BasedOnAlignment

ResizeBehavior 属性是一个枚举类型:GridResizeBehavior ,这个枚举类型包含以下枚举项:

BasedOnAlignment    根据VerticalAlignment 和 HorizontalAlignment 属性来确定分割线移动后,有哪些项被移动
CurrentAndNext        Grid 当前所在的区域以及下一个区域被影响
PreviousAndCurrent  前一个和当前区域被影响
PreviousAndNext      前一个和后一个区域被影响

我们把这个XAML文件改成下面方式就可以左右联动了。注意,只改动了加粗,加红的这一个属性。

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="WpfApplication_GridSplitter.Window1"
    Title="Window1" Height="100" Width="300">
    <Grid Width="Auto" Height="Auto" >
        <Grid.ColumnDefinitions >
            <ColumnDefinition Width="*"  />
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="5*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions />
        <StackPanel Grid.Column="0"  Background="DarkBlue" />
        <GridSplitter Grid.Column="1"  Width="3" Background="Red"

ResizeBehavior="PreviousAndNext" />
        <StackPanel Grid.Column="2"  Background="#FFAEA130" />
    </Grid>
</Window>

改动后的效果图:

GridSplitter 的 ResizeBehavior 属性介绍03

总结:

GridSplitter 的默认 ResizeBehavior 属性导致我们无法实现左右联动,我们只需要简单的修改这个属性就实现左右联动。

这个问题,由于是第一次接触WPF,让我花了好几个星期,才发现是这里简单的问题所导致的。所以特写此篇博客,希望对碰到这个问题人有所帮助。

参考资料:

MSDN GridResizeBehavior Enumeration

posted on 2007-09-03 20:42:00 by ghj1976  评论(4) 阅读(5260)

使用Grid来对WPF页面进行布局排版

       对于以前用 Windows Form 来开发客户端程序的程序员,在使用 WPF 开发客户端的程序时,在窗体布局上将是他必须面对的一个坎。

       布局产生困惑的一个典型场景如下:

       我们在开发WPF窗体时候,我们会发现,当我们把菜单控件(Menu)、工具条(ToolBar、ToolBarPanel)、状态条(StatusBar)这些最常见的页面元素拖动到WPF窗体的时候。我们会发现 WPF 窗体中,这些页面元素可以放置在任何位置,而不是之前 Windows Form 那样:主菜单在最上面,状态条在最下面。

       WPF中每一个元素如何布局变得更加灵活了,这样可以让美工更好的设计出更漂亮的页面,但是也会让一些缺乏艺术细胞的技术人员页面布局变得巨难看无比。比如我最近在写个简单的调查系统客户端维护工具,使用WPF程序来开发,这个页面布局的事情,就让我非常头大。

       WPF 跟布局有关的控件很多,System.Windows.Controls.Panel 是这些所有布局有关的类的基类。需要注意的是,我们在页面布局上一般都是使用这个类的扩展类来处理布局,而不是使用这个类。这些扩展类包括:

System.Windows.Controls.Canvas  (画布)
System.Windows.Controls.DockPanel  (停靠布局)
System.Windows.Controls.Grid    (表格)
System.Windows.Controls.StackPanel   (堆栈布局)
System.Windows.Controls.VirtualizingPanel  (虚堆栈布局)
System.Windows.Controls.WrapPanel  (覆盖布局)

       我自己在使用中觉得:对于我们从Window Form 习惯来的技术人员,使用 Grid    (表格) 布局就可以满足我们绝大多数的布局需求,而且简单。下面我们就来介绍如何使用 Grid 布局控件来进行窗体布局设计。

       Grid 布局控件很类似 HTML 标签中的 Table 标签。我们事先把一个区域划分成不同的表格,然后决定,某些控件放在那个表格中,那些控件是要跨多少个表格来放置。比如下面窗体效果,是由后面的XAML文件来实现这个效果的。

WPF窗体的一个效果图

这个窗口布局上,我使用了Grid控件

我把这个窗口首先划分成三行三列的一个Grid。如上图我对这个窗体的拆分。

最上面的显示多少条目,以及下拉列表框,以及刷新按钮,被放在第一行,跨三列

未发布的调查表列表框被放在第二行,第一列,

支持来回拖动的GridSplitter被我放在了第二列,第二行

ListView 则被我放在了第二行,第三列

最下面的确定,取消按钮被我放在了第三行,跨了三个列

上述界面效果的XAML文件如下:

 

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="HongjunGuo.SurveySystem.Client.QuestionnaireList"
    Title="调查列表" Height="300" Width="500">
    <Grid >
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="150"/>
            <ColumnDefinition Width="5" />
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="35"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="35"/>
        </Grid.RowDefinitions>

        <DockPanel Height="30" Name="dockPanel2" Grid.ColumnSpan="3" Grid.Row="0">
            <Label>显示多少条目:</Label>
            <ComboBox Height="21" Name="comboBox1" Width="120" >
                <ComboBoxItem IsSelected="True" >5</ComboBoxItem>
                <ComboBoxItem>10</ComboBoxItem>
                <ComboBoxItem>20</ComboBoxItem>
                <ComboBoxItem>50</ComboBoxItem>
            </ComboBox>
            <Button Height="23" Name="button1" Width="75">刷新</Button>
        </DockPanel>

        <ListBox IsSynchronizedWithCurrentItem="True" Name="lb_Type"  Width="Auto" Grid.Column="0" Grid.Row="1"  >
            <ListBoxItem Name="lbi_Draft" ToolTip="最近使用的,并且没有被发布的调查表" Content="本地未发布的调查表草稿" Height="50" IsSelected="True"/>
            <ListBoxItem Name="lbi_Release" Content="本地最近发布的调查表" Height="50"/>
            <ListBoxItem Name="lbi_Seatch" Content="服务器上的调查列表" Height="50"/>
        </ListBox>
        <GridSplitter Grid.Column="1" Grid.Row="1" HorizontalAlignment="Left" Name="gridSplitter1" Width="10" />
        <ListView Name="lv_Data" IsSynchronizedWithCurrentItem="True" Grid.Column="3" Grid.Row="1">
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="编号">
                    </GridViewColumn>
                    <GridViewColumn Header="标题">
                    </GridViewColumn>
                    <GridViewColumn Header="创建时间">
                    </GridViewColumn>
                </GridView>
            </ListView.View>
        </ListView>

        <DockPanel Height="30" Name="dockPanel4"  Grid.ColumnSpan="3" Grid.Row="2">
            <Button Height="23" Name="btn_OK" Width="75" IsDefault="True" Click="btn_OK_Click">确 定</Button>

            <Button Height="23" Name="btn_Cancel" Width="75" IsCancel="True">取 消</Button>
        </DockPanel>
    </Grid>
</Window>

使用Grid布局控件的时候,一些知识点如下:

我们可以通过定义Grid的ColumnDifinitions和RowDifinitions来实现对于表格的定义,然后根据Grid.Column和Grid.Row的对象来制定位置的方式实现布局。

比如上面XAML文件中

    <Grid >
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="150"/>
            <ColumnDefinition Width="5" />
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="35"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="35"/>
        </Grid.RowDefinitions>

就定义了一个三行三列的表格。

ColumnDefinition 和 RowDefinition 分别只需要定义 Width 和 Height

如果我们希望列的宽度或者行的高度是根据内部元素来决定的,我们可以定义为 Auto, 如果我们希望某列或者某行的宽度或者告诉是整体的其他部分,则可以定义成 *,如果我们希望其中一项的长度是另外一项的5倍,则可以一个定义成*,一个定义成5* 。

我们看 ColumnDefinition  或者 RowDefinition  的 Width 或者 Height 属性的时候,我们可以看到这个属性不是 int或者 double 类型,而是 GridLength 类型。

下面一个简单的Grid定义来演示上面定义长度的几种写法

<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <Grid >
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="30"/>
            <ColumnDefinition Width="auto" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="2*" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>

        <Label Grid.Column="0" Grid.Row="0" Background="RosyBrown"  ></Label>
        <Label Grid.Column="1" Grid.Row="0" Background="SkyBlue"  >1234567890</Label>
        <Label Grid.Column="2" Grid.Row="0" Background="Red"  ></Label>

        <Label Grid.Column="0" Grid.Row="1" Background="SpringGreen"  ></Label>
        <Label Grid.Column="1" Grid.Row="1" Background="RoyalBlue"  >abc</Label>
        <Label Grid.Column="2" Grid.Row="1" Background="Violet"  ></Label>

    </Grid>
</Window>

这个XAML文件的效果图如下:

使用Grid进行布局

此外,我们还可以使用 Grid.ColumnSpan Grid.RowSpan 来实现一块布局跨多个表格项的情况。

 

小结:

我个人觉得,把一个窗体或者页面用表格拆分,然后我们在每个表格项中增加我们规划好的控件,这种布局方案在没有比较好的美术细胞下,比较容易做出一个至少不难看的页面布局。

基于以上的考虑,我觉得我们技术人员开发一些WPF窗体或者页面的时候,Grid控件应该是我们最常用到的。也应该是最应该掌握的控件。

 

参考资料:

WPF基本版面布局(精简版)

.Net Framework3.0 实践纪实(1)

posted on 2007-08-17 13:44:00 by ghj1976  评论(5) 阅读(6460)