WPF编程入门

长平狐 发布于 2012/08/28 16:37
阅读 1K+
收藏 0

 

    开发准备

    WPF编程是微软推出的打破GUI编程旧模式的创新技术。全称为WINDOWS PRESENTATION FOUNDATION。开发工具建议使用Visual Studio 2008 Team System。语言建议使用C#。WPF可以更方便的开发更漂亮的界面,并且可以比以前更好地将GUI设计和程序逻辑分离开来,使得有条件的公司可以专门培养平面设计人员进行GUI设计(有点类似于与网页美工),而程序员更加关注业务逻辑。
    

    一个简单的示例开始

创建一个WPF工程,工程名为Demo。



请注意图中灰色区域,那是一个XAML文件,如果不用VS2008图形化设计工具,光写XAML文件,我们也可以设计出GUI界面来。理解XAML的一些基本知识很重要,但是还是推荐使用图形化设计工具来工作,毕竟谁都想生活轻松点。
这个工程新建好了以后,就创建了一个窗口应用程序。现在只有一个窗口而已,窗口标题为默认的Window1。下面是运行的结果:

   理解XAML

XAML全称为Extensible Application Markup Language 。XAML可以用来编写WPF,但是也可以做很多其他的事情。每个WPF程序都有一个Application对象,该对象代表了整个应用程序,它总是有一个static Main方法。如何编写一个Application类有多种方法,可以参考 http://www.cnblogs.com/kuku/archive/2007/02/09/645623.html 。但是这篇文章写得较早,最新的VS2008有些变化。所以下面我说明一下,App.xaml内容如下:
<Application x:Class="Demo.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    StartupUri="Window1.xaml">
    <Application.Resources>
        
    </Application.Resources>
</Application>
    
         
   


Application元素的x:Class属性的值为Demo名字空间里面的类App。该类的定义如下:
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Windows;

namespace Demo
{
    ///
    /// Interaction logic for App.xaml
    ///
    public partial class App : Application
    {
    }
}

我们并不需要写static Main方法,估计编译器替我们生成了。 App.xaml中的Application元素还有一个属性StartupUri指定了应用程序开始运行时显示的第一个窗口Window1。Window1.xaml文件内容如下:
<Window x:Class="Demo.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>
   


这个应该比较容易懂,除了指定Demo.Window1为窗口类以外,还指定了Title,Height,Width属性的值。Window1类的代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
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;

namespace Demo
{
    ///
    /// Interaction logic for Window1.xaml
    ///
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
        }
    }
}
   Window1继承了System.Windows.Window类。InitializeComponent()方法的主要作用是读取Window1.xaml文件中指定的Window元素的属性值。代码如下:
        [System.Diagnostics.DebuggerNonUserCodeAttribute()]
        public void InitializeComponent() {
            if (_contentLoaded) {
                return;
            }
            _contentLoaded = true;
            System.Uri resourceLocater = new System.Uri("/Demo;component/window1.xaml", System.UriKind.Relative);
           
            #line 1 "....Window1.xaml"
            System.Windows.Application.LoadComponent(this, resourceLocater);
           
            #line default
            #line hidden
        }

    添加两个控件,并理解事件处理机制

现在我打算添加一个文本控件,然后再添加一个按钮,当按钮点击后,文本控件的内容将被修改。通过Toolbox拖拽TextBox和Button到Window1窗口上。现在的Window1.xaml文件内容变成:
<Window x:Class="Demo.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>
        <TextBox Height="23" Margin="80,46,78,0" Name="textBox1" VerticalAlignment="Top" />
        <Button Height="23" Margin="101,0,103,59" Name="button1" VerticalAlignment="Bottom">Press</Button>
    </Grid>
</Window>

Grid控件用来精确的定位控件的位置。现在Grid包含了两个子控件。Button控件显示的文本Press被<Button...>和</Button>包在中间。

注意观察Press按钮的三个箭头,直指正下方的箭头代表了VerticalAlignment="Bottom",垂直对齐方式为底部对齐。左右两个箭头都存在,所以水平对齐方式没有。Name属性对应C#代码里面的按钮对象名称。Margin属性的四个值分别为left,top,right,margin。注意,这是和对齐方式有关系的,和我们平时习惯的窗口左上角为原点不同。由于现在是垂直方向底边对齐,所以top总是为0。
现在来为Press按钮增加一个单击事件,在xaml文件中增加一个事件<Button Height="23" Margin="104,0,98,73" Name="button1" VerticalAlignment="Bottom" Click="button1_Click" >Press</Button>。这里已经不再采用传统的事件选择的方式,而是在xaml文件中直接通过提示选择。VS2008同时将会创建一个成员函数button1_Click,代码如下:
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {

        }
    }
熟悉.Net WinForm开发的人应该很能猜到这里仍然使用委托机制来实现事件回调。sender就代表事件源,这里其实就是Window1对象自己。RoutedEvnetArgs e可以让我们获得事件的相关信息。我们添加一句
System.Windows.MessageBox.Show("You click me"),这样点击按钮后就会弹出一个消息框。
到这里,一个麻雀虽小,但是五脏俱全的例子程序就结束了。使用xml编写界面的方式的确比以前用代码来编写直观,并且降低了门槛,让具备美术功底的设计人员可以参与进来。但是由于界面直接和软件功能有关,所以要做到界面设计和代码编写完全分离还不可能。
后面我会陆续总结一些编写优美界面的知识。

BitmapEffect特效

这篇文章介绍得很详细,请参考:
    http://www.cnblogs.com/kuku/archive/2007/02/11/647533.html

无标题栏的圆角窗口

  
通常特殊形状的窗口都要去掉标题栏,所以Window对象的属性WindowStyle要设置为"None",将背景设为透明,并且允许透明。代码如下:
<Window x:Class="Demo.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" WindowStyle="None" Background="Transparent" AllowsTransparency="True">

我们可以通过增加一个Border元素,设置四个转角的角度,代码如下:
<Grid Name="Border">
        <Border CornerRadius="5,5,5,5" ></Border>
        <TextBox Height="23" Margin="85,61,73,0" Name="textBox1" VerticalAlignment="Top" />
        <Button Height="23" Margin="104,0,98,73" Name="button1" VerticalAlignment="Bottom" Click="button1_Click">Press</Button>
</Grid>


没有了标题栏,我们还要允许拖拽窗口,因此需要处理鼠标左键的单击事件。代码如下:
<Window x:Class="Demo.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" WindowStyle="None" Background="Transparent" AllowsTransparency="True" MouseLeftButtonDown="Window_MouseLeftButtonDown">
    <Grid Name="Border">
        <Border CornerRadius="5,5,5,5" Background="AliceBlue" ></Border>
        <TextBox Height="23" Margin="85,61,73,0" Name="textBox1" VerticalAlignment="Top" />
        <Button Height="23" Margin="104,0,98,73" Name="button1" VerticalAlignment="Bottom" Click="button1_Click">Press</Button>
    </Grid>
</Window>
注意,Border的背景色不能为透明,否则无法拖拽。 Window_MouseLeftButtonDown函数的实现非常简单。请看:
namespace Demo
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            System.Windows.MessageBox.Show("You click me");
        }

        private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            DragMove();
        }

    }
}


所以整个效果看上去应该这样:

线性递增画刷

该画刷可以绘制渐变的效果,真得很方便。比如下面的代码:
<Window x:Class="Demo.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" WindowStyle="None" Background="Transparent" AllowsTransparency="True" MouseLeftButtonDown="Window_MouseLeftButtonDown" Name="Resources">
    <Window.Resources>
       
    </Window.Resources>
    <Grid Name="Border">
        <Border CornerRadius="5,5,5,5" Background="AliceBlue"></Border>
        <TextBox Height="23" Margin="85,61,73,0" Name="textBox1" VerticalAlignment="Top" />
        <Button Content="Press" Height="23" Margin="104,0,98,73" Name="button1" VerticalAlignment="Bottom" Click="button1_Click">
            <Button.Background>
                <LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
                    <GradientStop Offset="0" Color="Yellow"></GradientStop>
                    <GradientStop Offset="0.5" Color="Green"></GradientStop>
                    <GradientStop Offset="1" Color="Red"></GradientStop>
                </LinearGradientBrush>
            </Button.Background>

        </Button>
    </Grid>
</Window>
    
        


    这种xml嵌套使用的方式似乎通过vs2008的可视化编辑工具做不出来,还是需要手动编辑xaml文件。

Content 模式

凡是从ContentControl类派生的控件都能够容纳别的子控件。比如下面的例子来自于<<Programming WPF>>。
<Window ...>
    <Button Width="100" Height="100">
        <TextBox Width="75">edit me
        </TextBox>
    </Button>
</Window> 


    界面如下:


你也可以这么使用,这种情况更适合嵌入对象。
<Button Width="100" Height="100">
    <Button.Content>
        <Image Source="tom.png" />
    </Button.Content>
</Button>

Grid布局控件

    有些控件,提供了很方便的布局功能,比如Grid,它使用表格的方式放置它的子控件。下面的示例,同样来自于<<Programming WPF>>::
<Window ...>





<Grid>





<Grid.RowDefinitions>





<RowDefinition />





<RowDefinition />





<RowDefinition />





</Grid.RowDefinitions>





<Grid.ColumnDefinitions>





<ColumnDefinition />





<ColumnDefinition />





<ColumnDefinition />





</Grid.ColumnDefinitions>





<Button Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2




">A</Button>





<Button Grid.Row="0" Grid.Column="2




">C</Button>





<Button Grid.Row="1" Grid.Column="0" Grid.RowSpan="2




">D</Button>





<Button Grid.Row="1" Grid.Column="1




">E</Button>





<Button Grid.Row="1" Grid.Column="2




">F</Button>





<Button Grid.Row="2" Grid.Column="1




">H</Button>





<Button Grid.Row="2" Grid.Column="2




">I</Button>





</Grid>





</Window>

 

    使用Grid.RowDefinitions子元素定义了三行,使用Grid.ColumnDefinitions定义了三列。 Grid.ColumnSpan="2 "指定了A按钮占用两列空间。

ListView控件

    下面的代码定义了三个Header,名称分别为Name,Email和Address。
            <ListView Name="list">
                <ListView.View>
                    <GridView ColumnHeaderToolTip="freebird">
                        <GridViewColumn  Header="Name" Width="100" DisplayMemberBinding="{Binding Path=FirstName}" />
                        <GridViewColumn  Header="Email" Width="100" DisplayMemberBinding="{Binding Path=Email}" />
                        <GridViewColumn  Header="Address" Width="100" DisplayMemberBinding="{Binding Path=Address}" />
                    </GridView>
                </ListView.View>
            </ListView>
    DisplayMemberBinding="{Binding Path=FirstName}" 指的是该列的要显示的内容和后面ItemSource所指的对象的属性FirstName绑定。
     效果如下:
   通常数据都是从数据源(比如数据库)获得,然后通过代码插入到ListView控件中,因此下面演示如何通过代码插入数据:
ListView有一个属性IEnumerable ItemsSource。ItemsSource代表ListView里面的Item的集合。我们应该为ItemsSource赋予一个数据集合对象,该集合对象的类型是继承自ObservableCollection<>,ObservableCollection最终也是继承自IEnumerable接口。如果ListView的每个Item(代表一行纪录)对应一个Person类。Person代码如下:(注意这里的属性名称和前面xaml文件里面的绑定名称相同)
 public class Person
    {
        public Person(String name, String email, String address)
        {
            this.name = name;
            this.email = email;
            this.address = address;
        }

        private String name;
        private String email;
        private String address;

        public String Name
        {
            get
            {
                return name;
            }

            set
            {
                name = value;
            }
        }

        public String Email
        {
            get
            {
                return email;
            }

            set
            {
                email = value;
            }
        }

        public String Address
        {
            get
            {
                return address;
            }

            set
            {
                address = value;
            }
        }
    }
   
    Item的集合可以容纳多个Item。我设计了Persons类代表Item的集合,代码如下:
public class Persons : ObservableCollection
    {
        public Persons()
        {
            Add(new Person("chenshu","csfreebird@gmail.com","101"));
            Add(new Person("lijing", "sheismylife@sina.com", "102"));
        }
    }
    Persons的构造函数将创建两个Person对象作为两个Item。然后往ListView里面填写数据的代码就很简单了:
   public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
            list.ItemsSource = new Persons();
        }
        ..........
    }

    还有一种更加简单的做法。利用ListView.Items属性的Add方法将Person对象逐个加入。比如下面的代码:
list.Items.Add(new Person("chenshu", "csfreebird@gmail.com", "d"));






 


原文链接:http://blog.csdn.net/sheismylife/article/details/4668771
加载中
返回顶部
顶部