演练:用 WPF 设计器生成简单的 WPF 应用程序
更新:2007 年 11 月
本演练演示如何使用 WPF 设计器生成简单的 Windows Presentation Foundation (WPF) 应用程序。
在本演练中,您将执行下列任务:
创建项目。
创建布局。
向布局添加控件。
设置与布局相关的属性。
创建数据源。
连接到数据源。
绑定控件属性。
在完成本演练后,您将具有一个可用来浏览文件系统的简单应用程序。该应用程序的用户界面将用可扩展应用程序标记语言 (XAML) 来实现。有关更多信息,请参见 XAML。下面的插图说明您的应用程序将如何显示。
![]() |
---|
显示的对话框和菜单命令可能会与“帮助”中的描述不同,具体取决于您的当前设置或版本。若要更改设置,请在“工具”菜单上选择“导入和导出设置”。有关更多信息,请参见 Visual Studio 设置。 |
先决条件
您需要以下组件来完成本演练:
- Visual Studio 2008。
创建项目
第一步是为应用程序创建项目。
创建项目
使用 Visual Basic 或 Visual C# 创建一个名为 FolderExplorer 的新 WPF 应用程序项目。有关更多信息,请参见如何:创建新的 WPF 应用程序项目。
Window1.xaml 在 WPF 设计器中打开。
在“设计”视图中,选择该窗口。有关更多信息,请参见如何:在设计图面上选择和移动元素。
在“属性”窗口中,将 Title 属性的值设置为 Folder Explorer。
创建布局
布局定义控件在应用程序的主窗口中的排列方式。下面的步骤演示如何构造将包含应用程序控件的布局元素。
创建布局
在窗口上选择 Grid 根控件。
向网格中添加第二行。有关更多信息,请参见如何:向网格中添加行和列。
向网格中添加第二列。
向布局添加控件
定义了布局后,可用控件来填充布局。只需在“工具箱”中单击所需控件并将该控件拖动到设计图面上。
向布局添加控件
从“工具箱”中将一个 TreeView 控件拖动到网格的第一个单元格中。根据需要调整该控件的大小。
从“工具箱”中将一个 ListView 控件拖动到占据网格第一行第二列的单元格中。根据需要调整该控件的大小。
从“工具箱”中将一个 ListView 控件拖动到占据网格第二行第二列的单元格中。根据需要调整该控件的大小。
设置与布局相关的属性
下面的步骤演示如何对控件设置与布局相关的属性。在对每个控件设置属性时,布局将越来越接近最终的应用程序。
设置与布局相关的属性
选择 TreeView 控件。
在“属性”窗口中,如下所示设置下列属性。
属性
值
Grid.ColumnSpan
1
Grid.RowSpan
2
Height
Auto
HorizontalAlignment
Stretch
Margin
0,0,0,0
VerticalAlignment
Stretch
Width
Auto
TreeView 控件将调整大小,以适合第一个网格列,并跨越两个网格行。
同时选择两个 ListView 控件。
在“属性”窗口中,如下所示设置下列属性。
属性
值
Grid.ColumnSpan
1
Grid.RowSpan
1
Height
Auto
HorizontalAlignment
Stretch
Margin
0,0,0,0
VerticalAlignment
Stretch
Width
Auto
ListView 控件将调整大小,以适合其各自的网格单元格。
在“文档大纲”窗口中,展开网格的“ColumnDefinitions”节点。有关更多信息,请参见浏览 WPF 文档的元素层次结构。
选择第一个“ColumnDefinition”项。
在“属性”窗口中,将 Width 属性设置为 *。
在“文档大纲”窗口中,选择第二个“ColumnDefinition”。
在“属性”窗口中,将 Width 属性设置为 2*。
两列将重新调整大小,第一列占窗口宽度的三分之一,第二列占三分之二。
在“文档大纲”窗口中,展开网格的“RowDefinitions”节点。
选择第一个“RowDefinition”项。
在“属性”窗口中,将 Height 属性设置为 *。
在“文档大纲”窗口中,选择第二个“RowDefinition”。
在“属性”窗口中,将 Height 属性设置为 *。
行的大小将重新调整为占窗口高度的一半。
生成并运行项目。
创建数据源
FolderExplorer 应用程序的数据源是一个名为 Folder 的类。此类提供文件系统的简单模型。每个 Folder 实例都有一个 SubFolders 和一个 Files 集合。
创建数据源
将一个名为 Folder 的新类添加到 FolderExplorer 项目。有关更多信息,请参见如何:添加新项目项。
用下面的代码替换 Folder 源代码文件的内容。
Imports System Imports System.IO Imports System.Linq Imports System.Collections.Generic Imports System.Collections.ObjectModel Imports System.Text Public Class Folder Private _folder As DirectoryInfo Private _subFolders As ObservableCollection(Of Folder) Private _files As ObservableCollection(Of FileInfo) Public Sub New() Me.FullPath = "c:\" End Sub 'New Public ReadOnly Property Name() As String Get Return Me._folder.Name End Get End Property Public Property FullPath() As String Get Return Me._folder.FullName End Get Set If Directory.Exists(value) Then Me._folder = New DirectoryInfo(value) Else Throw New ArgumentException("must exist", "fullPath") End If End Set End Property ReadOnly Property Files() As ObservableCollection(Of FileInfo) Get If Me._files Is Nothing Then Me._files = New ObservableCollection(Of FileInfo) Dim fi As FileInfo() = Me._folder.GetFiles() Dim i As Integer For i = 0 To fi.Length - 1 Me._files.Add(fi(i)) Next i End If Return Me._files End Get End Property ReadOnly Property SubFolders() As ObservableCollection(Of Folder) Get If Me._subFolders Is Nothing Then Try Me._subFolders = New ObservableCollection(Of Folder) Dim di As DirectoryInfo() = Me._folder.GetDirectories() Dim i As Integer For i = 0 To di.Length - 1 Dim newFolder As New Folder() newFolder.FullPath = di(i).FullName Me._subFolders.Add(newFolder) Next i Catch ex As Exception System.Diagnostics.Trace.WriteLine(ex.Message) End Try End If Return Me._subFolders End Get End Property End Class
using System; using System.IO; using System.Linq; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Text; namespace FolderExplorer { public class Folder { private DirectoryInfo _folder; private ObservableCollection<Folder> _subFolders; private ObservableCollection<FileInfo> _files; public Folder() { this.FullPath = @"c:\"; } public string Name { get { return this._folder.Name; } } public string FullPath { get { return this._folder.FullName; } set { if (Directory.Exists(value)) { this._folder = new DirectoryInfo(value); } else { throw new ArgumentException("must exist", "fullPath"); } } } public ObservableCollection<FileInfo> Files { get { if (this._files == null) { this._files = new ObservableCollection<FileInfo>(); FileInfo[] fi = this._folder.GetFiles(); for (int i = 0; i < fi.Length; i++) { this._files.Add(fi[i]); } } return this._files; } } public ObservableCollection<Folder> SubFolders { get { if (this._subFolders == null) { this._subFolders = new ObservableCollection<Folder>(); DirectoryInfo[] di = this._folder.GetDirectories(); for (int i = 0; i < di.Length; i++) { Folder newFolder = new Folder(); newFolder.FullPath = di[i].FullName; this._subFolders.Add(newFolder); } } return this._subFolders; } } } }
连接到数据源
WPF 控件通过数据绑定连接到数据源。下面的过程演示如何声明和绑定到 ObjectDataProvider。
连接到数据源
在 WPF 设计器中打开 Window1.xaml。
在 XAML 视图中,向 <Window> 标记中插入以下 XAML 以及其他 xmlns 映射。有关更多信息,请参见如何:将命名空间导入 XAML。
xmlns:my="clr-namespace:FolderExplorer"
在 <Window> 开始标记后以及 <Grid> 开始标记前插入以下 XAML。
<Window.Resources> <ObjectDataProvider x:Key="RootFolderDataProvider" > <ObjectDataProvider.ObjectInstance> <my:Folder FullPath="c:\"/> </ObjectDataProvider.ObjectInstance> </ObjectDataProvider> <HierarchicalDataTemplate DataType = "{x:Type my:Folder}" ItemsSource = "{Binding Path=SubFolders}"> <TextBlock Text="{Binding Path=Name}" /> </HierarchicalDataTemplate> </Window.Resources>
<Window.Resources> <ObjectDataProvider x:Key="RootFolderDataProvider" > <ObjectDataProvider.ObjectInstance> <my:Folder FullPath="c:\"/> </ObjectDataProvider.ObjectInstance> </ObjectDataProvider> <HierarchicalDataTemplate DataType = "{x:Type my:Folder}" ItemsSource = "{Binding Path=SubFolders}"> <TextBlock Text="{Binding Path=Name}" /> </HierarchicalDataTemplate> </Window.Resources>
用下面的 XAML 替换 <TreeView> 标记。
<TreeView Grid.ColumnSpan="1" Grid.RowSpan="2" Margin="0,0,0,0" Name="treeView1" > <TreeViewItem ItemsSource="{Binding Path=SubFolders, Source={StaticResource RootFolderDataProvider}}" Header="Folders" /> </TreeView>
<TreeView Grid.ColumnSpan="1" Grid.RowSpan="2" Margin="0,0,0,0" Name="treeView1" > <TreeViewItem ItemsSource="{Binding Path=SubFolders, Source={StaticResource RootFolderDataProvider}}" Header="Folders" /> </TreeView>
绑定控件属性
可将一个控件的属性绑定到其他控件,这将启用自动属性更新。
绑定控件属性
在 XAML 视图中,将两个 <ListView> 标记均替换为以下 XAML。
<ListView Name="listView1" ItemsSource="{Binding Path=SelectedItem.SubFolders, ElementName=treeView1, Mode=OneWay}" Grid.Column="1" Grid.RowSpan="1" /> <ListView Name="listView2" ItemsSource="{Binding Path=SelectedItem.Files, ElementName=treeView1, Mode=OneWay}" Grid.Column="1" Grid.Row="1" />
<ListView Name="listView1" ItemsSource="{Binding Path=SelectedItem.SubFolders, ElementName=treeView1, Mode=OneWay}" Grid.Column="1" Grid.RowSpan="1" /> <ListView Name="listView2" ItemsSource="{Binding Path=SelectedItem.Files, ElementName=treeView1, Mode=OneWay}" Grid.Column="1" Grid.Row="1" />
生成并运行项目。
展开“Folders”项,以打开根文件夹。通过单击子文件夹和查看两个 ListView 控件的内容来进行试验。子文件夹显示在上面的 ListView 控件中,文件显示在下面的 ListView 控件中。
后续步骤
当前,FolderExplorer 应用程序以默认样式来显示。您可以应用自己的样式来更改应用程序的外观和行为。
Visual Studio 还提供了许多用于调试 WPF 应用程序的工具。有关更多信息,请参见演练:在设计时调试 WPF 自定义控件。