65.9K
CodeProject 正在变化。 阅读更多。
Home

WPF 分步教程:WPF 和 Expression Blend 入门

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.97/5 (112投票s)

2010年8月5日

CPOL

20分钟阅读

viewsIcon

362589

downloadIcon

6353

使用 Microsoft Expression Blend 4.0 开始您的第一个 WPF 应用程序。

引言

Windows Presentation Foundation 为开发应用程序提供了一种绝佳的方式。然而,WPF 的入门可能会令人望而生畏。数据绑定、MVVM、XAML、像素着色器、控件模板、样式、资源和触发器等术语很可能都让您感到陌生。

本文将帮助您开始学习 WPF。我们将创建一个简单的应用程序,并逐步讲解其中的要点。读完本文后,您将熟悉 WPF 开发的一些核心概念,并能够很好地利用 WPF 的强大功能来创建出色的应用程序。

WPF 的一大优点是它鼓励您使用一种合理的软件编写模式——将内容与设计分离,将业务逻辑与 UI 分离。您将编写出组织良好、易于测试和维护的代码。

背景

本文中的代码是 C#。Visual Basic 代码也会非常相似。如果大家有足够的兴趣,我会用 VB 代码更新本文。我使用的是最新的平台和技术——Expression Blend 4、Visual Studio 2010 和 .NET Framework 4.0。

创建新项目

前言到此为止。让我们直接开始吧。我们将从简单入手,构建一个骨架应用程序,然后对我们的基础应用程序进行完善。我们将采用一种非常实践的方法,而不是用技术细节和抽象概念轰炸您。

首先,打开 Expression Blend 4 并选择“新建项目”。我将这个项目命名为 WpfStepByStep1——任何名字都可以!

New Project Window

我们得到了一些文件。一些 C# 文件和一些 XAML 文件。XAML 是可扩展应用程序标记语言。我们用它来布局窗口和 UI 元素。XAML 与 HTML 非常相似;它允许我们布局窗口、排列控件等等。我们将大量使用 XAML,但现在,让我们先看看我们得到了什么。按 F5,或转到“项目” > “运行项目”。

Main Window

虽然没什么可看的,但我们确实已经得到了不少东西。一个新窗口,一个供我们安排内容的空白区域,以及 Windows 应用程序中常见的特性(关闭按钮等)。有一点值得注意——我们可以调整窗口大小、最小化和最大化。在 HTML 的世界里,我们很少知道用户的屏幕有多大——或者他们的浏览器窗口有多大。因此,我们很少依赖*绝对定位*,比如“这个按钮距离左边 30 像素”。我们尝试以一种内容可以优雅地调整大小的方式来安排窗口或页面。WPF 可以很好地做到这一点——我们将确保我们的应用程序无论窗口大小如何都能正常工作。

添加一些控件

如果您对 WPF 和 Expression Blend 完全不熟悉,现在是尝试的好时机。左侧的“资产”面板有一个“控件”部分。点击它。现在资产面板中会显示一组控件。

Assets Panel

我们可以使用各种熟悉和不熟悉的控件。还有一些形状可以玩。稍后,我们甚至会看看效果和动画。Expression Blend 的设计窗口是为 UI 设计量身打造的——当项目被移动和调整大小时,会提供视觉提示。事实上,呈现的某些数据可能看起来有点令人困惑。现在,我们先接受可以快速将控件拖放到窗口上的事实。

Controls

删除您添加的任何控件——我们将创建一个功能性应用程序,需要一个干净的画布。在本文中,我们将创建一个地址簿。这不是最有创意的想法,但它足够简单,可以让我们了解一些我们感兴趣的功能。

开始制作地址簿

我们决定编写一个简单的地址簿应用程序,以便管理我们联系人的一些信息。通常,这时我们会开始考虑我们想要呈现的信息、UI 可能的外观、需要实现的功能需求等等。现在,我将通过给您一个简要说明来加快进度

我想要一个简单的地址簿应用。我需要以下功能

  • 查看联系人。
  • 添加新联系人。
  • 查看简单的联系人详细信息——姓名、电子邮件地址和电话号码。

除此之外,我决定让它看起来大致像这样

UI Prototype

如果您对我如何制作上面的图片感兴趣,请告诉我。Expression Blend 有一个名为“SketchFlow”的强大 UI 原型制作工具,它使模拟 UI 设计、添加动画、收集客户反馈等变得前所未有的简单。这本身就是一个大话题,但如果大家有足够的兴趣,我会在这个系列中写一篇关于 SketchFlow 的文章。

对于这样的项目,动手实践的方法非常棒。上面的草图很基础,但已经足够完整,可以让我们初步尝试 UI。请按照以下步骤操作

  • 在“资产”面板中找到“Text Block”控件(如果找不到,有一个方便的搜索框)。Text Block 用于显示文本块——类似于 Win32/MFC 中的 Static,或 Windows Forms 中的 Label。将 Text Block 拖到设计图面上。
  • 通过从左侧工具栏顶部选择较深的箭头来进入选择模式。单击文本块并打开右侧的“属性”面板。在“通用属性”选项卡中找到“Text”属性,并将其更改为“Address Book”。
  • Text Block Properties

  • 将一个“List Box”控件拖到窗口的左侧——我们将在这里显示联系人列表。
  • 在窗口右侧创建另一个文本块,并将其文本设置为“Contact Details”。
  • 创建 UI 原型中显示的三个文本块。
  • 提示: 通过拖动副本来加快速度。选择一个文本块并按住 Alt 键。将该文本块拖到其他地方。松开后,就会创建一个副本。即使您选择了控件组,这也能正常工作。

  • 将三个“Text Box”控件拖到窗口上。像 UI 原型中那样排列它们。
  • 最后,将一个“Button”控件拖到设计图面上,并将其内容设置为“Create a New Contact”。将其放置在原型所示的位置。

您现在应该得到类似这样的东西

Address Book

在这个阶段,您可以更仔细地看看“属性”面板。我们布局的控件可以使用“属性”面板进行广泛的修改。我们可以更改字体、颜色、画笔、视觉效果等等。请记住,在“属性”窗口的每个面板底部都有一条小栏——按下它可以查看更高级的属性。也要习惯使用搜索框——当您对 Blend 和 WPF 越来越熟悉时,它会派上用场。

按 F5。我们有了一个好的开始,控件都在那里并且位置适当。调整窗口大小。根据您布局控件的方式,您会看到控件重新定位和调整大小的各种行为。无论如何,调整大小的行为可能不完美——我们稍后会回到这个问题。现在,我们继续完成一些功能。

创建对象

根据需求说明,我们对需要什么样的数据对象有了相当清晰的认识。一个 Contact 对象将包含姓名、电子邮件地址和电话号码。整个应用程序将包含一组联系人。

在 Expression Blend 中,转到“项目” > “新建项”,然后创建一个名为“Contact.cs”的类文件。

New Class

这个 `Contact` 类将非常简单。源代码如下

using System;

namespace WpfStepByStep1
{
    public class Contact
    {
        public Contact()
        {
        }
        
        public string Name
        {
            get;
            set;
        }
        
        public string Email
        {
            get;
            set;
        }
        
        public string PhoneNumber
        {
            get;
            set;
        }
    }
}

没有比这更容易的了。如果您已经接触过 Model-View-ViewModel,别担心——我们很快就会讲到它。现在,我们先让事情尽可能简单。

我们现在遇到了第一个真正的 WPF 挑战——我们应该把联系人放在哪里?是在 XAML 中吗?在 `App` 类中?还是在 `MainWindow` 类中?这类问题会引起困惑——您可能听说过数据应该放在模型中,并用视图模型来呈现——但这些实体是什么?它们又存在于哪里?我们稍后会回到这个问题;现在,我们先选择看起来最快的解决方案——然后,我们再看看如何用 WPF 的方式来做,事实证明这种方式甚至更快!

从项目面板中打开 MainWindow.xaml.cs 文件。

MainWindow.xaml.cs

如下所示,向类中添加一个联系人列表。

public partial class MainWindow : Window
{
    public MainWindow()
    {
        this.InitializeComponent();
        // Insert code required on object
        // creation below this point.
    }
        
    protected List<Contact> contacts = new List<Contact>();

    public List<Contact> Contacts
    {
        get { return contacts; }
        set { contacts = value; }
    }
}

为了确保我们的 UI 正常工作,我们需要一些数据,所以在 `MainWindow` 对象的构造函数中添加几个联系人。

public MainWindow()
{
    this.InitializeComponent();

    //    Add some contacts.
    contacts.Add(new Contact() {Name = "James", 
                 Email = "james@mail.com", 
                 PhoneNumber = "01234 111111"} );
    contacts.Add(new Contact() {Name = "Bob", Email = "bob@mail.com", 
                 PhoneNumber = "01234 222222"} );
    contacts.Add(new Contact() {Name = "Emma", Email = "emma@mail.com", 
                 PhoneNumber = "01234 333333"} );
}

最后,我们需要将它与窗口联系起来。WPF 有自己的方式来做这件事,叫做*数据绑定*。我们稍后会详细讨论这个。在一个典型的 WinForms 应用程序中,我们可能会遍历联系人列表,为每个联系人创建一个列表视图项,将其标签设置为数据对象,然后插入到列表框中。而在 WPF 中,我们会告诉列表视图“这是你的数据”,然后让它接管。我们用现有的数据也可以做到这一点,但这有点绕。构建项目。打开 *MainWindow.xaml* 文件,以便您可以看到控件。单击左侧的列表框,找到“`ItemsSource`”属性。通过点击旁边的小方块打开高级属性,然后选择“数据绑定”。

Item Source

我们可以通过在顶部选择“`Element`”并找到“`Contacts`”属性来绑定到 `MainWindow` 对象的“`Contacts`”属性。

Data Binding

按“确定”并按 F5。我们可以在列表控件中看到三个联系人对象。但这并不是特别有用。而且,找到那个属性有点麻烦。当我们有越来越多的属性,并且可能想要将它们相互关联时,会发生什么?这就是 MVVM (Model-View-ViewModel) 设计模式发挥作用的地方。

MVVM

MVVM 背后的思想是:我们的应用程序有三个元素

模型

模型(Model)是应用程序数据。它可以来自数据库、文件、内存或其他任何地方。模型很可能包含业务逻辑和一些非常复杂的实体。

View

视图(View)是应用程序的表示层。在本例中,它是控制显示内容和渲染方式的 XAML 文件。

ViewModel

视图模型(ViewModel)是将这两者联系在一起的对象。在我们的例子中,ViewModel 将包含我们正在显示的联系人列表、当前联系人以及视图可能需要连接的任何其他内容。

这是 MVVM 的最基本概述。和之前的概念一样,我们将通过使用它来学习这个模式。我们从上面的几点知道,ViewModel 是一个将内容与表示层联系起来的对象。那么,让我们动手写一个吧。视图必须显示联系人以及所选联系人的详细信息,所以我们将把这些数据放在一个视图模型类中。创建一个名为 `AddressBookViewModel` 的新类。

public class AddressBookViewModel
{
    public AddressBookViewModel()
    {
    }

    protected List<Contact> contacts = new List<Contact>();
    
    protected Contact selectedContact = null;
    
    public List<Contact> Contacts
    {
        get { return contacts; }
        set { contacts = value; }
    }
    
    public Contact SelectedContact
    {
        get { return selectedContact; }
        set { selectedContact = value; }
    }
}

这个类将保存我们要呈现的所有数据。从 *MainWindow.xaml.cs* 文件中删除“`contacts`”成员和“`Contacts`”属性——我们不再需要它们了。同时也要移除我们在构造函数中添加联系人的那几行代码。

ViewModel 实例存储在哪里?这是另一个会引起困惑的问题。是视图请求一个 ViewModel,还是应用程序创建 ViewModel 并将其设置到视图中?我们如何将它们联系在一起?简短的回答是,我们将在窗口对象中拥有 ViewModel 的单个实例。但我们将在不添加任何一行代码的情况下做到这一点。接下来的几个步骤非常重要——您可能会在应用程序的每个窗口中都使用它们。

通过点击列表框“`ItemsSource`”属性上的“重置”高级属性弹出窗口,删除我们之前设置的绑定。构建项目。在设计器中通过双击项目面板中的 *MainWindow.xaml* 文件来选择 MainWindow。它下方有一个“对象和时间线”面板。这显示了窗口中内容的视觉树。窗口是顶层对象。选中它后,转到“属性”面板并找到“Data Context”。

Data Context Property

搜索功能是不是很有用?如果您还没用过,试试看——它会为您节省大量时间。`DataContext` 可以被认为是我们要将 UI 元素绑定到的对象或数据。它是分层的,所以通过在窗口中设置它,我们为所有控件设置了数据上下文——我们可以设置一次就不用管它了。我们的计划是将窗口的数据上下文设置为 ViewModel 的一个实例——这将大大简化事情。点击“新建”。

Select Object

我们几乎可以把任何东西设置为数据上下文。搜索“view”或“viewmodel”,然后选择 `AddressBookViewModel` 类。选择“确定”。现在我们已经设置了数据上下文,选择左侧的列表框,然后回到“Items Source”属性。按下高级按钮并选择“数据绑定”。我们现在可以在顶部使用“Data Context”选项卡——并且我们有了可以使用的 `AddressBookViewModel` 对象。选择“Contacts”并按“确定”。

Create Data Binding

我们现在正在使用数据上下文并直接绑定到联系人。这实际上做了什么?通过按窗口右上角下方的小图标进入“拆分”视图。数据上下文已在 XAML 的顶部附近设置

<Window.DataContext>
    <local:AddressBookViewModel />
</Window.DataContext> 

我们已经告诉窗口,它的数据上下文是我们 `AddressBookViewModel` 类的一个实例。如果我们添加“`x:Name`”属性,我们甚至可以在代码隐藏(code-behind)中使用它。将 XAML 更改为这样

<Window.DataContext>
    <local:AddressBookViewModel x:Name="ViewModel" />
</Window.DataContext>

我们现在已经给这个实例命名了。转到 *MainWindow.xaml.cs* 中的 `MainWindow` 构造函数,并修改它以添加一些联系人

public MainWindow()
{
    this.InitializeComponent();

    //    Add some contacts.
    ViewModel.Contacts.Add(new Contact() {Name = "James", 
                           Email = "james@mail.com", 
                           PhoneNumber = "01234 111111"} );

    ViewModel.Contacts.Add(new Contact() {Name = "Bob", 
                           Email = "bob@mail.com", 
                           PhoneNumber = "01234 222222"} );

    ViewModel.Contacts.Add(new Contact() {Name = "Emma", 
                           Email = "emma@mail.com", 
                           PhoneNumber = "01234 333333"} );
}

这很聪明。我们在 XAML 中创建的对象在代码隐藏中是可用的。

让我们变得更聪明。用和我们之前设置数据绑定相同的方式,设置以下的绑定

  • 对于列表框,将“`SelectedItem`”属性绑定到“Selected Contact”。
  • 在“Name”文本框中,将“`Text`”属性绑定到“SelectedContact > Name”属性(“SelectedContact”可以展开以显示其成员)。
  • 在“Email”文本框中,将“`Text`”属性绑定到“SelectedContact > Email”属性。
  • 在“Phone”文本框中,将“`Text`”属性绑定到“SelectedContact > PhoneNumber”属性。

按 F5。我们得到了和以前一样的列表——但是因为我们告诉列表将其选定项绑定到 ViewModel 中的“`SelectedContact`”属性,所以在列表中选择一项会设置“`SelectedContact`”属性。这三个文本框绑定到“`SelectedObject`”的各种属性——所以当我们改变选择时,文本框会更新。编辑每个文本框中的文本,然后切换到另一个联系人——再切换回来。我们的更改被保留了——所选对象只是对我们“Contacts”列表中某一项的引用,所以所有东西都完美地联系在一起了。请记住——我们为使应用程序的 UI 正常工作所做的唯一代码是在构造函数中设置一些简单的联系人——我们实际上是在没有离开设计器的情况下就将文本框和列表控件联系起来了。

属性更改通知

我们忽略了一些微妙的东西。如果您继续用这种方法构建应用程序,您很快会注意到缺少了某些东西——当我们以编程方式更改 ViewModel 属性时,UI 不会更新。为了演示这一点,我们将更新程序,以便在窗口加载时,自动选择第一个联系人。

在设计器中打开 *MainWindow.xaml* 文件。在“对象和时间线”面板中,双击树顶部的“Window”项以选择主窗口。转到“属性”面板并选择“事件”。事件图标在右上角,如下所示

Events

我们可以处理一大堆事件,但现在,我们想要的是 `Loaded` 事件。在列表中找到它,然后双击“Loaded”标签右侧的文本框。这将为我们创建事件处理程序,并将在代码编辑器中打开它。更改事件处理程序以选择第一个联系人。

private void Window_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
    //    Set the 'SelectedContact' of the view model to the first contact.
    ViewModel.SelectedContact = ViewModel.Contacts[0];
}

运行程序。第一个联系人并未显示为选中状态。那么问题出在哪里?

我将为您节省一些使用调试器的时间(您必须在 Visual Studio 中使用它!)。您编写的代码**正在**被调用,但是 UI 不知道 `SelectedContact` 已经改变了。那么我们该怎么做呢?

在 WinForms 或 Win32 应用程序中,我们需要告诉 UI 对象已经改变了;我们可能会调用 `Invalidate`、`Refresh` 或类似的函数。这并不是特别好;这意味着我们的一小块业务逻辑需要知道 UI,它必须知道要更新什么。如果当所选联系人改变时我们需要做很多事情怎么办?我们将要做的是调整 ViewModel 来实现 `INotifyPropertyChanged` 接口。这个接口允许我们在属性改变时发送一个通知;任何注册接收此通知的东西都将被更新。如果我们在 ViewModel 中实现这个接口,那么 UI 将被通知属性已经改变并相应地更新自己。

创建一个新的类文件,名为 `ViewModelEntity`,如下所示

using System;
using System.ComponentModel;

namespace WpfStepByStep1
{
     /// <summary>
     /// Standard viewmodel class base, simply allows
     /// property change notifications to be sent.
     /// </summary>
     public class ViewModelEntity : INotifyPropertyChanged
     {
         /// <summary>
         /// The property changed event.
         /// </summary>
         public event PropertyChangedEventHandler PropertyChanged;
        
         /// <summary>
         /// Raises the property changed event.
         /// </summary>
         /// <param name="propertyName">Name
         ///              of the property.</param>
         public virtual void NotifyPropertyChanged(string propertyName)
         {
             //  If the event has been subscribed to, fire it.
             if (PropertyChanged != null)
                 PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
         }
     }
}

我们现在可以调整我们的 ViewModel 类来使用这个接口。如下所示进行更改,更改部分以粗体显示

public class AddressBookViewModel : ViewModelEntity
{
    public AddressBookViewModel()
    {
    }
 
    protected List<Contact> contacts = new List<Contact>();
 
    protected Contact selectedContact = null;
 
    public List<Contact> Contacts
    {
        get { return contacts; }
        set { contacts = value; }
    }
 
    public Contact SelectedContact
    {
        get { return selectedContact; }
        set 
        { 
            if(selectedContact != value)
            {
                selectedContact = value;
                NotifyPropertyChanged("SelectedContact");
            }
        }
    }
}

当 `SelectedContact` 被设置时,我们检查它是否被设置为不同的值。如果是,我们就设置它并引发事件。运行程序。现在列表中的第一项被选中了,并且所有的文本框都已更新。

我们什么时候需要这样做?简而言之,几乎总是需要。我们现在可以忽略 `Contact` 对象,因为我们没有通过编程方式更改它的任何属性。但如果我们这样做了,我们就需要使用同样的方法。在这种情况下,我们可能会将它包装在一个 `ContactViewModel` 类中,以保持 ViewModel 的特殊性分开。我们还应该做另一个更改,同样用粗体显示。

// Keep everything else the same as before - only change
// the Contacts member and property.

protected ObservableCollection<Contact> contacts = 
            new ObservableCollection<Contact>();
 
public ObservableCollection<Contact> Contacts
{
    get { return contacts; }
    set { contacts = value; }
}

要让这个构建成功,您需要在文件顶部添加一行 `using System.Collections.ObjectModel;`。`ObservableCollection` 是一个在添加或删除项目时会发送通知的集合。现在如果我们更改集合,视图将会自动更新。为什么我们不需要在 `Contacts` 属性的 `set` 部分调用 `NotifyPropertyChanged` 函数呢?因为我们没有改变对集合的引用——我们改变的是集合*中*的项目。所以使用 `ObservableCollection` 就足够了。如果我们要在许多不同的集合之间切换,我们就需要像 `SelectedContact` 属性那样调用这个函数。

MVVM

我们现在已经在我们的应用程序中使用了 Model-View-ViewModel 模式。在我们的模型中,我们有一个基本的 `Contact` 对象。对于我们的视图,我们有 MainWindow XAML。并且我们有一个专门的 `AddressBookViewModel` 对象来将这两者联系在一起。我们可以将业务逻辑和数据层与数据的表示层分开;当您习惯了这种模式后,它会变得越来越有意义。WPF 的一个优点是,它确实会迫使您使用这种方法来充分利用它——这将帮助您设计和编写更好的代码。

继续

还有一些事情要做。首先,左边的列表框显示的是它所显示对象的名称,但我们想要的是联系人姓名。在设计器中选择列表框,找到“`DisplayMemberPath`”属性。将其设置为“`Name`”。

DisplayMemberPath

运行应用程序。我们现在在列表中看到了 `Contact` 对象的 `Name` 属性。这是快速得到我们想要结果的方法。我们可以在 XAML 中创建一个 `ItemTemplate` 来做更多的事情——比如显示姓名,下面以超链接形式显示电子邮件地址等等,但那是一个更高级的话题。

现在我们将名称设置为显示成员,我们可以看到我们仍然有一个限制。在右侧的文本框中更改联系人姓名并不会更新列表框。我们现在知道为什么了——该属性正在被列表框更改,但该属性在更改时不会发送通知。我们需要更改 `Contact` 对象,使其派生自 `ViewModelEntity` 并发送通知。代码如下

public class Contact : ViewModelEntity
{
    public Contact()
    {
    }
 
    protected string name;
    protected string email;
    protected string phonenumber;
 
    public string Name
    {
        get {return name;}
        set
        {
            if(name != value)
            {
                name = value;
                NotifyPropertyChanged("Name");
            }
        }
    }
 
     public string Email
     {
         get {return email;}
         set
         {
             if(email != value)
             {
                 email = value;
                 NotifyPropertyChanged("Email");
            }
        }
    }
 
     public string PhoneNumber
     {
        get {return phonenumber;}
         set
        {
             if(phonenumber != value)
             {
                 phonenumber = value;
                 NotifyPropertyChanged("PhoneNumber");
             }
         }
     }
}

进行更改并运行程序。现在当您更改名称并从控件中跳出或选择另一个联系人时,列表会更新。`Name` 属性实际上直到我们离开文本框后才会被更改。

添加新数据

我们希望让“Create New Contact”按钮工作。在设计器中选择它,转到事件(在属性面板中),然后选择“Click”。双击文本框以创建一个事件处理程序,并添加下面的代码

private void Button_Click(object sender, System.Windows.RoutedEventArgs e)
{
    //    Create a new contact.
    Contact contact = new Contact() {Name = "New Contact"};
 
    //    Add it to the list.
    ViewModel.Contacts.Add(contact);
 
    //    Set it as the selected contact.
    ViewModel.SelectedContact = contact;
}

在经历了设置数据上下文和创建一些视图模型实体的初步复杂性之后,我们现在可以非常迅速地实现业务逻辑了。在上面的代码中,我们没有告诉 UI 更新,我们不关心视图是显示列表还是如何显示自己。我们设置的绑定处理了这方面的事情,而 XAML 控制着渲染。

回到 MVVM

顺便提一下,值得指出的是,既然我们已经到了这个阶段,我们离理想的 MVVM 模式更近了一步。`Contact` 对象实际上已经变成了本质上的 `ContactViewModel` 实体。联系人数据可能会存储在文件或数据库中——这些将是 Contact *Model* 实体——从这些实体中,我们创建 Contact *ViewModel* 实体——它们可能大不相同。例如,`ContactViewModel` 实体可能想要存储其他数据——比如它是否已被更改(或许可以允许视图显示一个“保存更改”按钮)。

我们并非一开始就使用 MVVM 模式,而是因为需要而逐渐转向它。现在我们正在使用它,我们可以轻松地扩展这个应用程序。

后续步骤

我们在地址簿应用程序上还有很多工作要做。它不能很好地处理窗口大小调整,不能持久化数据,而且看起来非常基础。但我们已经涵盖了很多内容——创建一个新应用程序,使用数据上下文和数据绑定,`INotifyPropertyChanged`,以及 `ObservableCollection`。希望您在这个过程中对 Expression Blend 更加熟悉了。这是我计划的一系列文章中的第一篇——任何反馈都将非常棒——请告诉我您喜欢或不喜欢什么,以及任何不清楚的地方。您希望接下来学习什么?请发邮件到 dwmkerr@googlemail.com 告诉我——我会根据大家似乎想学习的内容来写下一步的分步指南。例如

  • 布局:使用网格和面板来布局控件。
  • 样式:使用样式和模板自定义控件。
  • 数据:设计时数据、XML 和更多 CLR。

Visual Studio 2010 vs. Expression Blend 4

一起使用它们!Expression Blend 非常适合布局、设计和样式设置,但对于任何非琐碎的代码相关工作,都需要 Visual Studio。我总是同时打开两者,并且同时使用它们。

这个项目也可以用同样的方式在 Visual Studio 中编写。它的数据绑定编辑器功能稍弱,并且在可视化创建数据上下文等方面做得不太好,但当您对 XAML 更熟悉一些时,您可能会最终手写很多 XAML。Expression Blend 是设计 UI 的首选,但 Visual Studio 通常是编写代码隐藏所必需的。

历史

  • 2010年8月5日:初版。
© . All rights reserved.