利用 C# 开发 WPF 应用程序
1. 开发背景与选择
Microsoft 目前提供了两种创建桌面应用程序的方式:Windows Forms(自 .NET 1.0 起使用的技术)和 Windows Presentation Foundation(WPF,.NET 3.5 新增)。无论采用哪种技术,C# 语言本身变化不大。本文将重点介绍如何使用 C# 事件处理程序创建一个相对简单但有一定复杂度的 WPF 应用程序。
WPF 大部分是用声明性语言 XAML 编写的,XAML 即可扩展应用程序标记语言,是行业标准 XML 的一种方言,很容易被 Visual Studio 等工具读取和操作。
2. 示例程序介绍
我们要创建的示例程序是从白宫网站拉取美国前 20 位总统的图片,并将它们展示在一个自定义的 WPF 控件中。由于控件宽度有限,无法同时显示所有 20 张图片,因此会提供一个水平滚动条。当用户鼠标悬停在某张图片上时,图片会放大(从 75 变为 85),不透明度从 75% 增加到 100%;鼠标移开后,图片恢复到初始的较小尺寸和较低透明度。此外,当用户点击图片时,会通过 C# 事件处理程序捕获点击事件,显示总统的名字,并将其显示在控件的标题栏中。
3. 构建应用程序步骤
3.1 创建项目
打开 Visual Studio 2008,选择“Create ➝ Project”。在“New Project”对话框中,选择 .NET Framework 3.5,在“Project Types”窗口中选择“Visual C#”,在“Templates”窗口中选择“WPF Application”。选择程序的保存位置并命名(例如“Presidential Browser”)。
Visual Studio 会创建一个包含窗口的初始应用程序,窗口内有一个空的网格。界面会显示为上下分割窗口,上方是设计器,下方是 XAML 代码。
3.2 布局设计
WPF 提供了两种布局对象:堆栈面板(Stack Panels)和网格(Grids)。堆栈面板可以将一组对象堆叠在一起,网格则类似于表格,有行和列。
我们要创建一个两行一列的简单网格,每行内放置一个堆栈面板。顶部堆栈面板用于显示文本“United States Presidents”,底部堆栈面板用于放置包含照片的列表框。
以下是初始的 XAML 代码:
<Window x:Class="Presidential_Browser.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 Width="300" Height="180">
<Grid.RowDefinitions>
<RowDefinition Height="70" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0">
<TextBlock Text="Top Stack Panel" VerticalAlignment="Center"/>
</StackPanel>
<StackPanel Grid.Row="1">
<TextBlock Text="Bottom Stack Panel" VerticalAlignment="Center"/>
</StackPanel>
</Grid>
</Window>
对代码进行分析:
- 前 3 行声明了 WPF 的标准命名空间。
- 接着是窗口的标题、高度和宽度。
- 然后是网格的声明及其高度。
- 在网格内,通过 Grid.RowDefinition 声明来精确控制行间距的分配,将 7/18 的空间分配给第一行。
- 定义了两个堆栈面板,每个面板内放置一个文本块,用于显示简单文本并将其居中对齐。
我们可以将第一个堆栈面板中的文本块修改为:
<TextBlock FontSize="14" Grid.Row="0" >United States Presidents</TextBlock>
同时,可以调整行的分配,将第一行高度设为 20,其余空间分配给第二行,并将网格高度设为 170。
3.3 资源创建与样式设置
为了实现图片的滚动显示和交互效果,我们需要创建一些资源和样式。
首先,在 XAML 文件顶部创建一个线性渐变画刷 ListBoxGradient :
<Window.Resources>
<LinearGradientBrush x:Key="ListBoxGradient"
StartPoint="0,0"
EndPoint="0,1">
<GradientStop Color="#90000000" Offset="0" />
<GradientStop Color="#40000000" Offset="0.005" />
<GradientStop Color="#10000000" Offset="0.04" />
<GradientStop Color="#20000000" Offset="0.945" />
<GradientStop Color="#60FFFFFF" Offset="1" />
</LinearGradientBrush>
</Window.Resources>
这个线性渐变画刷可以用于绘制填充,颜色会从顶部到底部逐渐变化。
接着,定义一个列表框的样式 SpecialListStyle :
<Style x:Key="SpecialListStyle"
TargetType="{x:Type ListBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBox}" >
<Border BorderBrush="Gray"
BorderThickness="1"
CornerRadius="6"
Background="{DynamicResource ListBoxGradient}" >
<ScrollViewer VerticalScrollBarVisibility="Disabled"
HorizontalScrollBarVisibility="Visible">
<StackPanel IsItemsHost="True"
Orientation="Horizontal"
HorizontalAlignment="Left" />
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
该样式会为列表框创建一个灰色边框,使用 ListBoxGradient 作为背景,禁用垂直滚动条,启用水平滚动条,并使列表框水平显示。
然后,定义列表框项的样式 SpecialListItem :
<Style x:Key="SpecialListItem"
TargetType="{x:Type ListBoxItem}">
<Setter Property="MaxHeight" Value="75" />
<Setter Property="MinHeight" Value="75" />
<Setter Property="Opacity" Value=".75" />
<Style.Triggers>
<EventTrigger RoutedEvent="Mouse.MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Duration="0:0:0.2"
Storyboard.TargetProperty="MaxHeight" To="85" />
<DoubleAnimation Duration="0:0:0.2"
Storyboard.TargetProperty="Opacity" To="1.0" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="Mouse.MouseLeave">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Duration="0:0:1"
Storyboard.TargetProperty="MaxHeight" />
<DoubleAnimation Duration="0:0:0.2"
Storyboard.TargetProperty="Opacity" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
</Style>
该样式设置了列表框项的初始最大高度、最小高度和不透明度,并通过触发器实现鼠标悬停和移开时的动画效果。
3.4 添加数据
我们将数据直接放在资源中,而不是从 Web 服务或数据库获取。首先需要创建两个类: ImageURL 和 Images 。
ImageURL 类代码如下:
using System;
using System.Collections.Generic;
using System.Windows.Media.Imaging;
namespace PhotoCatalog
{
public class ImageURL
{
public string Path { get; private set; }
public Uri ImageURI { get; set; }
public BitmapFrame Image { get; private set; }
public string Name { get; set; }
public ImageURL( ) { }
public ImageURL(string path, string name)
{
Path = path;
ImageURI = new Uri(Path);
Image = BitmapFrame.Create(ImageURI);
Name = name;
}
public override string ToString( )
{
return Path;
}
}
public class Images : List<ImageURL> { }
}
ImageURL 类用于封装图片信息, Images 类继承自 List<ImageURL> ,作为 List<ImageURL> 的别名。
在 XAML 中创建 Images 类的实例并添加数据:
<local:Images x:Key="Presidents">
<local:ImageURL ImageURI="http://www.whitehouse.gov/history/presidents/images/gw1.gif" Name="George Washington" />
<!-- 重复添加 20 次,每次对应一位总统 -->
</local:Images>
这相当于在 C# 中编写:
List<ImageURL> Presidents = new List<ImageURL>( );
ImageURL newImage = new ImageURL("http://www.whitehouse.gov/history/presidents/images/gw1.gif", "George Washington");
Presidents.Add(newImage);
3.5 使用数据并定义列表框
为网格提供数据上下文:
<Grid Width="300" Height="170"
DataContext="{StaticResource Presidents}">
然后在第二个堆栈面板中定义列表框:
<StackPanel Grid.Row="1" Grid.ColumnSpan="3" >
<ListBox Style="{StaticResource SpecialListStyle}"
Name="PresPhotoListBox" Margin="0,0,0,20"
SelectionChanged="PresPhotoListBox_SelectionChanged"
ItemsSource="{Binding }"
IsSynchronizedWithCurrentItem="True" SelectedIndex="0"
ItemContainerStyle="{StaticResource SpecialListItem}" >
</StackPanel>
这样,列表框就会使用之前定义的样式和数据,实现图片的滚动显示和交互效果。
总结
通过以上步骤,我们利用 C# 和 XAML 成功创建了一个 WPF 应用程序,实现了从网络获取图片、布局设计、样式设置以及交互效果等功能。在开发过程中,我们充分利用了 WPF 的布局对象、资源和样式,以及 C# 的事件处理机制。
以下是整个开发流程的 mermaid 流程图:
graph TD;
A[创建项目] --> B[布局设计];
B --> C[资源创建与样式设置];
C --> D[添加数据];
D --> E[使用数据并定义列表框];
表格总结关键步骤:
| 步骤 | 操作 |
| ---- | ---- |
| 创建项目 | 打开 Visual Studio 2008,选择“Create ➝ Project”,配置相关选项 |
| 布局设计 | 创建网格和堆栈面板,设置文本块 |
| 资源创建与样式设置 | 创建线性渐变画刷、列表框样式和列表框项样式 |
| 添加数据 | 创建 ImageURL 和 Images 类,在 XAML 中添加数据 |
| 使用数据并定义列表框 | 为网格设置数据上下文,定义列表框 |
利用 C# 开发 WPF 应用程序(续)
4. 深入理解关键技术点
4.1 XAML 与 C# 的协同工作
在这个 WPF 应用程序中,XAML 和 C# 起到了相辅相成的作用。XAML 主要负责界面的布局和样式定义,而 C# 则用于实现逻辑处理和事件响应。
例如,在前面的代码中,XAML 定义了窗口、网格、堆栈面板、列表框等界面元素的布局和样式,如下所示:
<Window x:Class="Presidential_Browser.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">
<!-- 其他 XAML 代码 -->
</Window>
而 C# 则用于处理列表框的选择更改事件,虽然在前面未详细展示,但可以推测在事件处理方法 PresPhotoListBox_SelectionChanged 中会有相应的逻辑处理:
private void PresPhotoListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
// 处理选择更改事件的逻辑
}
4.2 动画与触发器机制
WPF 中的动画和触发器机制为界面交互提供了丰富的效果。在列表框项的样式 SpecialListItem 中,我们使用了事件触发器来实现鼠标悬停和移开时的动画效果。
以下是鼠标悬停时的事件触发器代码:
<EventTrigger RoutedEvent="Mouse.MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Duration="0:0:0.2"
Storyboard.TargetProperty="MaxHeight" To="85" />
<DoubleAnimation Duration="0:0:0.2"
Storyboard.TargetProperty="Opacity" To="1.0" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
当鼠标进入列表框项时,会触发该事件触发器,开始执行故事板中的动画。 DoubleAnimation 用于对双精度数值类型的属性进行动画处理,这里分别对 MaxHeight 和 Opacity 属性进行了动画设置,使图片放大并变亮。
4.3 数据绑定机制
数据绑定是 WPF 的一个重要特性,它使得界面元素能够自动与数据源同步。在我们的示例中,通过为网格设置数据上下文:
<Grid Width="300" Height="170"
DataContext="{StaticResource Presidents}">
然后在列表框中使用 ItemsSource="{Binding }" 进行数据绑定:
<ListBox Style="{StaticResource SpecialListStyle}"
Name="PresPhotoListBox" Margin="0,0,0,20"
SelectionChanged="PresPhotoListBox_SelectionChanged"
ItemsSource="{Binding }"
IsSynchronizedWithCurrentItem="True" SelectedIndex="0"
ItemContainerStyle="{StaticResource SpecialListItem}" >
列表框会自动从 Presidents 数据源中获取数据并显示。这种数据绑定机制减少了手动更新界面的代码,提高了开发效率。
5. 可能的扩展与优化
5.1 数据加载优化
目前我们是将数据直接放在资源中,在实际应用中,可能需要从网络服务或数据库中动态加载数据。可以使用异步加载的方式,避免阻塞界面线程,提高用户体验。例如,使用 Task 或 async/await 关键字来实现异步数据加载:
private async void LoadDataAsync()
{
// 异步加载数据的逻辑
await Task.Run(() =>
{
// 从网络或数据库获取数据
});
// 更新界面
}
5.2 界面交互增强
可以进一步增强界面的交互效果,例如添加更多的动画效果、鼠标点击时的过渡动画等。还可以实现图片的缩放、旋转等操作,为用户提供更丰富的体验。
5.3 错误处理
在实际应用中,网络请求或数据加载可能会出现错误。需要添加错误处理机制,例如在数据加载失败时显示提示信息,避免应用程序崩溃。
try
{
// 可能会抛出异常的代码
}
catch (Exception ex)
{
// 处理异常,显示提示信息
MessageBox.Show($"Error: {ex.Message}");
}
总结与展望
通过本文的介绍,我们详细了解了如何使用 C# 和 XAML 开发一个 WPF 应用程序,包括项目创建、布局设计、样式设置、数据处理和交互效果实现等方面。WPF 提供了丰富的功能和强大的特性,使得开发人员能够创建出高质量的桌面应用程序。
在未来的开发中,我们可以进一步探索 WPF 的其他特性,如自定义控件、3D 效果等,不断提升应用程序的性能和用户体验。同时,结合现代的开发框架和工具,如 MVVM 模式,能够更好地组织代码,提高代码的可维护性和可扩展性。
以下是一个关于扩展与优化步骤的列表:
1. 实现异步数据加载,提高用户体验。
2. 增强界面交互效果,添加更多动画和操作。
3. 添加错误处理机制,确保应用程序的稳定性。
再来看一个关于关键技术点关系的 mermaid 流程图:
graph LR;
A[XAML] --> B[数据绑定];
B --> C[界面元素];
D[C#] --> E[事件处理];
E --> C;
F[动画与触发器] --> C;
表格总结扩展与优化方向:
| 扩展与优化方向 | 具体操作 |
| ---- | ---- |
| 数据加载优化 | 使用异步加载方式,如 Task 或 async/await |
| 界面交互增强 | 添加更多动画效果和操作,如缩放、旋转 |
| 错误处理 | 添加 try/catch 块,处理异常并显示提示信息 |
超级会员免费看

6万+

被折叠的 条评论
为什么被折叠?



