代码改变世界

[WPF]WPF中如何实现数据与表示分离。(一) —— XAML

2006-01-05 14:40  Colin Han  阅读(5068)  评论(0编辑  收藏  举报

软件复用一直是现代软件工程所追求的目标。提高软件复用性的一个关键点就是“数据表示分离”(表示:数据的展示方式)。
这个系列文章将以“如何分离数据与表示”做为主线,能够概要的介绍一些在WPF中引入的新的编程技术和概念。

在这个系列里面,我们将使用Kevin Moore的ColorPicker作为一个例子,通过逐渐深入的引入WPF中的新概念,来演示这些新概念对我们的开发有什么好处。

首先,让我们来介绍一下ColorPicker可以干什么?
        ColorPicker运行效果如下图:
       

通过拖动左边的Slider可以动态的改变右面预览窗口的背景颜色。

本系列文章将逐步的引入WPF中的概念,主要包括下面的几个步骤:
1. XAML
2. Binding
4. Convert.
3. Styling

我希望在每一阶段我们都尽量的将焦点集中在一个问题上,同时能够对这个问题相关的因素进行简单的介绍,以达到通过这个系列能够让大家对WPF有一个概括的了解。

OK, Let's GO...


在WPF中,微软引入了XAML(可扩展应用程序标记语言)的概念。其实XAML本不是一个新事物,在理论界已经经过多年的研究,应该说已经形成了一个相对成熟的体系。
简单来说,XAML就是一个应用程序界面的描述语言,(呵呵,这个描述可能并不准确,但是可能会更好理解一些)。就像我们以前编写VB程序或Delphi程序,会将界面按照一定的描述方式保存起来一样。
但是,XAML是基于XML的,因此,它与生俱来的具有XML的优势——跨平台,可扩展。

我们先来看一下如何用XAML来描述一个程序的界面:

<Window x:Class="Freezed.Window1"
    xmlns
="http://schemas.microsoft.com/winfx/avalon/2005"
    xmlns:x
="http://schemas.microsoft.com/winfx/xaml/2005"
    Title
="Color Picker"
    Height
="130" Width="300"
    
>
    
<Grid>
      <RowDefinition/>
      
<RowDefinition/>
      
<RowDefinition/>
      <ColumnDefinition Width="40"/>
      
<ColumnDefinition Width="150"/>
      
<ColumnDefinition Width="12"/>
      
<ColumnDefinition/>
      
      
<TextBlock Grid.Column="0" Grid.Row="0">Red:</TextBlock>
      <Slider Name="greenSlider" Grid.Column="1" Grid.Row="1"
              Minimum
="0" Maximum="255"              
              ValueChanged
="OnGreenSliderChanged"/>

      <TextBlock Name="redValue" Grid.Column="2" Grid.Row="0"/>
      
      
<TextBlock Grid.Column="0" Grid.Row="1">Green:</TextBlock>
      
<Slider Name="greenSlider" Grid.Column="1" Grid.Row="1"
              Minimum
="0" Maximum="255"              
              ValueChanged
="OnGreenSliderChanged"/>
      
<TextBlock Name="greenValue" Grid.Column="2" Grid.Row="1"/>
      
      
<TextBlock Grid.Column="0" Grid.Row="2">Blue:</TextBlock>
      
<Slider Name="blueSlider" Grid.Column="1" Grid.Row="2"
              Minimum
="0" Maximum="255"              
              ValueChanged
="OnBlueSliderChanged"/>
      
<TextBlock Name="blueValue" Grid.Column="2" Grid.Row="2"/>
      
      
<Border Grid.Column="3" Grid.Row="0" Grid.RowSpan="3" Margin="5, 5, 5, 5">
        
<Border Name="Preview" BorderThickness="1" CornerRadius="5" BorderBrush="Gray" Background="Black"/>
      
</Border>
    
</Grid>
</Window>

1. 对象
一般情况下,XML文件中的节点可以对应到一个对象或一个属性上。
各个节点之间的层次结构描述了节点之间的从属关系,例如:Window节点是这个XML的根节点,这个节点描述了一个Window对象,运行时,我们可以看到会弹出一个标准的Windows窗口出来。
这个Window对象中包含一个Grid对象,这个Grid中包含3个Slider,6个TextBlock和一个Border对象。加黄的部分是一段比较特殊的部分,后面我会专门写文章来讨论。

2. 属性
XAML中节点的属性对应到这个节点所描述对象的属性上。例如:上面的XAML中红色的部分描述了一个Slider对象,这个对象有3个属性:Minimum,Maximum,Name。Grid.Column和Grid.Row两个属性是附加属性
如果一个XAML中的节点包含属性Name,编译器将会在代码中生成一个同名的变量引用到这个对象上。这一点,是由IDE的CodeGenerical来实现的。相关的内容,如果以后有时间,我会专门写文章来讨论IDE的CodeGenerator。

3. 事件
XAML中的事件使用和属性相同的语法来描述。例如:Slider对象的ValueChanged是一个事件。它将映射到Code中的一个方法上。

Ok, 我们现在来看一下代码怎样编写:
 1using System;
 2using System.Windows;
 3using System.Windows.Controls;
 4using System.Windows.Data;
 5using System.Windows.Documents;
 6using System.Windows.Media;
 7using System.Windows.Shapes;
 8
 9namespace Freezed
10{
11    public partial class Window1 : Window
12    {
13        public Window1()
14        {
15            InitializeComponent();
16        }

17
18        Color _value = Colors.Black;
19
20        public void OnRedSliderChanged(Object sender, RoutedPropertyChangedEventArgs<double> e)
21        {
22            this._value = Color.FromArgb(_value.A, Convert.ToByte(e.NewValue), _value.G, _value.B);
23            this.OnValueChanged();
24        }

25        public void OnGreenSliderChanged(Object sender, RoutedPropertyChangedEventArgs<double> e)
26        {
27            this._value = Color.FromArgb(_value.A, _value.R, Convert.ToByte(e.NewValue), _value.B);
28            this.OnValueChanged();
29        }

30        public void OnBlueSliderChanged(Object sender, RoutedPropertyChangedEventArgs<double> e)
31        {
32            this._value = Color.FromArgb(_value.A, _value.R, _value.G, Convert.ToByte(e.NewValue));
33            this.OnValueChanged();
34        }

35
36        private void OnValueChanged()
37        {
38            this.Preview.Background = new SolidColorBrush(this._value);
39            this.redValue.Text = this._value.R.ToString();
40            this.greenValue.Text = this._value.G.ToString();
41            this.blueValue.Text = this._value.B.ToString();
42        }

43    }

44}
代码很简单,无非就是实现了XAML中声明调用的方法,然后同步几个对象的属性。

写到这里,发现这一章好像和“数据与表示分离”主题没有太多的关系。先作为预备知识,大家了解一下吧。因为后面的文章都会基于XAML来讨论。

XAML是WPF的核心概念之一。但是,很多人看到这里都会有这样的疑问:为什么要XAML?
微软引入XAML的一个主要的原因就是为了将界面和业务逻辑进行分离。在不远的将来,一个软件公司必须包含两类技术人才,一类是开发人员,而另一类就是设计人员。开发人员负责实现具体的业务逻辑,而设计人员仅仅进行UI的设计。他们的主要机能就是能够很好的操控XAML(与现在的WEB开发有点类似)。同时,微软正在开发新的设计器来实现可视化UI设计(花哨的就象Photoshop和CorelDraw)。

下面引用一篇老外的Blog供大家参考:If xaml is so easy, why is code so hard? 

下一篇Blog中,我们将讨论如何使用Binding实现数据与表示的分离。

本文的例子:ColorPicker1.rar
注意:本文相关的例子都在WinFX 11月CTP下测试通过,因为目前环境限制,没能再12月CTP下进行测试,请见谅。