WPF高级用法示例
一、MVVM模式深度实现
1. 命令模式扩展
cs
// RelayCommand.cs - 支持CanExecuteChanged事件和参数
public class RelayCommand : ICommand
{
private readonly Action<object> _execute;
private readonly Predicate<object> _canExecute;
public RelayCommand(Action<object> execute, Predicate<object> canExecute = null)
{
_execute = execute ?? throw new ArgumentNullException(nameof(execute));
_canExecute = canExecute;
}
public bool CanExecute(object parameter) => _canExecute == null || _canExecute(parameter);
public void Execute(object parameter) => _execute(parameter);
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
// 强制重新评估CanExecute
public void RaiseCanExecuteChanged() =>
CommandManager.InvalidateRequerySuggested();
}
2. ViewModel基类
cs
// ViewModelBase.cs - 实现INotifyPropertyChanged和IDisposable
public abstract class ViewModelBase : INotifyPropertyChanged, IDisposable
{
private bool _disposed = false;
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
protected bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, value)) return false;
field = value;
OnPropertyChanged(propertyName);
return true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
// 释放托管资源
}
_disposed = true;
}
}
~ViewModelBase() => Dispose(false);
}
3. 异步命令实现
cs
// AsyncRelayCommand.cs - 支持异步操作
public class AsyncRelayCommand : ICommand
{
private readonly Func<object, Task> _execute;
private readonly Predicate<object> _canExecute;
private bool _isExecuting;
public AsyncRelayCommand(Func<object, Task> execute, Predicate<object> canExecute = null)
{
_execute = execute ?? throw new ArgumentNullException(nameof(execute));
_canExecute = canExecute;
}
public bool CanExecute(object parameter) => !_isExecuting && (_canExecute == null || _canExecute(parameter));
public async void Execute(object parameter)
{
if (CanExecute(parameter))
{
try
{
_isExecuting = true;
RaiseCanExecuteChanged();
await _execute(parameter);
}
finally
{
_isExecuting = false;
RaiseCanExecuteChanged();
}
}
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void RaiseCanExecuteChanged() =>
CommandManager.InvalidateRequerySuggested();
}
二、高级数据绑定技术
1. 多绑定与转换器
XML
<!-- MultiBinding示例 -->
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} - {1}">
<Binding Path="FirstName"/>
<Binding Path="LastName"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
<!-- 使用IMultiValueConverter -->
public class FullNameConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values[0] is string firstName && values[1] is string lastName)
return $"{firstName} {lastName}";
return string.Empty;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
2. 动态数据模板
cs
<!-- 动态数据模板选择器 -->
public class ItemTypeTemplateSelector : DataTemplateSelector
{
public DataTemplate TextTemplate { get; set; }
public DataTemplate ImageTemplate { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
if (item is TextItem) return TextTemplate;
if (item is ImageItem) return ImageTemplate;
return base.SelectTemplate(item, container);
}
}
<!-- XAML中使用 -->
<DataTemplate x:Key="TextTemplate">
<TextBlock Text="{Binding Content}"/>
</DataTemplate>
<DataTemplate x:Key="ImageTemplate">
<Image Source="{Binding ImagePath}" Width="50" Height="50"/>
</DataTemplate>
<ListBox ItemsSource="{Binding Items}">
<ListBox.ItemTemplateSelector>
<local:ItemTypeTemplateSelector
TextTemplate="{StaticResource TextTemplate}"
ImageTemplate="{StaticResource ImageTemplate}"/>
</ListBox.ItemTemplateSelector>
</ListBox>
三、自定义控件开发
1. 自定义控件基类
cs
// CustomControlBase.cs - 提供通用功能
public abstract class CustomControlBase : Control
{
static CustomControlBase()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControlBase),
new FrameworkPropertyMetadata(typeof(CustomControlBase)));
}
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
// 模板应用后的初始化
}
}
2. 高级自定义控件示例
cs
<!-- 自定义进度条控件 -->
<Style TargetType="{x:Type local:AdvancedProgressBar}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:AdvancedProgressBar}">
<Grid>
<Border x:Name="PART_Border" Background="#FFEEEEEE" CornerRadius="5"/>
<Border x:Name="PART_Fill" Background="#FF4CAF50" CornerRadius="5"
Width="{TemplateBinding Value, Converter={StaticResource PercentageConverter}}"/>
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center"
Text="{TemplateBinding Value, StringFormat={}{0}%}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="Value" Value="100">
<Setter TargetName="PART_Fill" Property="Background" Value="#FF8BC34A"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
// 需要添加的依赖属性
public class AdvancedProgressBar : Control
{
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(double), typeof(AdvancedProgressBar),
new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsRender));
public double Value
{
get => (double)GetValue(ValueProperty);
set => SetValue(ValueProperty, value);
}
}
四、高级动画技术
1. 关键帧动画
cs
<!-- XAML关键帧动画 -->
<Window.Resources>
<Storyboard x:Key="FadeInOut">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:2" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:3" Value="0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</Window.Resources>
<!-- 触发动画 -->
<Button Content="播放动画" Click="PlayAnimation_Click"/>
private void PlayAnimation_Click(object sender, RoutedEventArgs e)
{
var story = (Storyboard)FindResource("FadeInOut");
story.Begin(this);
}
2. 自定义缓动函数
cs
// 自定义缓动函数
public class ElasticEaseConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is double progress && targetType == typeof(double))
{
// 实现弹性缓动效果
return Math.Sin(progress * Math.PI * (0.2f + 2.5f * progress * progress * progress))
* Math.Pow(1f - progress, 2.2f) + progress;
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
<!-- 使用自定义缓动 -->
<DoubleAnimation Duration="0:0:1" From="0" To="100" Storyboard.TargetProperty="Width">
<DoubleAnimation.EasingFunction>
<CubicEase EasingMode="EaseOut"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
五、高级数据可视化
1. 自定义图表控件
XML
<!-- 自定义折线图控件 -->
<ItemsControl ItemsSource="{Binding DataPoints}"
ItemTemplate="{StaticResource DataPointTemplate}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding X}"/>
<Setter Property="Canvas.Top" Value="{Binding Y}"/>
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
<DataTemplate x:Key="DataPointTemplate">
<Ellipse Width="5" Height="5" Fill="Red"/>
<Line X1="{Binding X}" Y1="{Binding Y}"
X2="{Binding Path=DataContext.PreviousPoint.X, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
Y2="{Binding Path=DataContext.PreviousPoint.Y, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
Stroke="Blue" StrokeThickness="2"/>
</DataTemplate>
2. 高级数据绑定示例
cs
<!-- 多级数据绑定与转换 -->
<TextBlock>
<TextBlock.Text>
<MultiBinding Converter="{StaticResource ComplexConverter}">
<Binding Path="Order.TotalAmount"/>
<Binding Path="Order.Discount"/>
<Binding Path="User.Currency"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
// 转换器实现
public class ComplexConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values[0] is decimal total && values[1] is decimal discount &&
values[2] is string currency)
{
var finalAmount = total - discount;
return $"{currency}{finalAmount:F2}";
}
return "N/A";
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
六、性能优化技术
1. 虚拟化列表
XML
<!-- 高性能数据网格 -->
<DataGrid VirtualizingStackPanel.IsVirtualizing="True"
VirtualizingStackPanel.VirtualizationMode="Recycling"
EnableRowVirtualization="True"
EnableColumnVirtualization="True"
ScrollViewer.IsDeferredScrollingEnabled="True">
<DataGrid.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel/>
</ItemsPanelTemplate>
</DataGrid.ItemsPanel>
</DataGrid>
2. 异步数据加载
cs
// ViewModel中的异步数据加载
public class DataViewModel : ViewModelBase
{
private ObservableCollection<DataItem> _items = new ObservableCollection<DataItem>();
public ObservableCollection<DataItem> Items => _items;
public async Task LoadDataAsync()
{
IsLoading = true;
try
{
var data = await DataService.GetDataAsync();
_items.Clear();
foreach (var item in data)
{
_items.Add(item);
}
}
finally
{
IsLoading = false;
}
}
private bool _isLoading;
public bool IsLoading
{
get => _isLoading;
set => SetField(ref _isLoading, value);
}
}
七、高级主题与样式
1. 动态主题切换
cs
<!-- 主题资源字典 -->
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Themes/LightTheme.xaml"/>
<!-- 或 DarkTheme.xaml -->
</ResourceDictionary.MergedDictionaries>
// 动态切换主题
public static class ThemeManager
{
public static void ApplyTheme(string themeName)
{
var dict = new ResourceDictionary
{
Source = new Uri($"Themes/{themeName}.xaml", UriKind.Relative)
};
Application.Current.Resources.MergedDictionaries.Clear();
Application.Current.Resources.MergedDictionaries.Add(dict);
}
}
2. 自定义控件样式
XML
<!-- 自定义按钮样式 -->
<Style TargetType="Button" x:Key="ModernButton">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
CornerRadius="4">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#FF4A90E2"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="#FF357ABD"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- 使用样式 -->
<Button Style="{StaticResource ModernButton}" Content="现代按钮"/>
八、高级布局技术
1. 自定义面板
cs
// 自定义流式面板
public class FlowPanel : Panel
{
public static readonly DependencyProperty OrientationProperty =
DependencyProperty.Register("Orientation", typeof(Orientation), typeof(FlowPanel),
new FrameworkPropertyMetadata(Orientation.Horizontal,
FrameworkPropertyMetadataOptions.AffectsArrange));
public Orientation Orientation
{
get => (Orientation)GetValue(OrientationProperty);
set => SetValue(OrientationProperty, value);
}
protected override Size MeasureOverride(Size availableSize)
{
// 测量逻辑...
return base.MeasureOverride(availableSize);
}
protected override Size ArrangeOverride(Size finalSize)
{
// 排列逻辑...
return base.ArrangeOverride(finalSize);
}
}
2. 复杂布局示例
XML
<!-- 响应式布局 -->
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal">
<TextBlock Text="标题" FontSize="20" FontWeight="Bold"/>
<Button Content="设置" Margin="10,0,0,0" Padding="5,2"/>
</StackPanel>
<ContentControl Grid.Row="1" Content="{Binding MainContent}"/>
<StatusBar Grid.Row="2">
<StatusBarItem>
<TextBlock Text="{Binding StatusMessage}"/>
</StatusBarItem>
<StatusBarItem HorizontalAlignment="Right">
<ProgressBar Width="100" Height="10" Value="{Binding Progress}"/>
</StatusBarItem>
</StatusBar>
</Grid>
九、高级调试技术
1. 可视化树调试
cs
// 获取可视化树结构
public static void PrintVisualTree(DependencyObject parent, int level = 0)
{
var indent = new string(' ', level * 2);
Debug.WriteLine($"{indent}{parent.GetType().Name}");
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
{
PrintVisualTree(VisualTreeHelper.GetChild(parent, i), level + 1);
}
}
// 使用方法
PrintVisualTree(this); // 从窗口开始打印
2. 性能分析工具
XML
<!-- 启用WPF性能分析 -->
<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="YourApp.App"
StartupUri="MainWindow.xaml">
<Application.Resources>
<!-- 启用性能计数器 -->
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Themes/DefaultTheme.xaml"/>
</ResourceDictionary.MergedDictionaries>
<!-- 性能分析设置 -->
<sys:Boolean x:Key="EnablePerformanceCounters">True</sys:Boolean>
</ResourceDictionary>
</Application.Resources>
</Application>
十、综合应用示例
1. 任务管理器示例
XML
<!-- 任务管理器主界面 -->
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="3*"/>
</Grid.ColumnDefinitions>
<!-- 左侧面板 - 进程列表 -->
<ListBox x:Name="ProcessList" Grid.Column="0" SelectionChanged="ProcessSelected">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Icon}" Width="16" Height="16" Margin="0,0,5,0"/>
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding CPUUsage, StringFormat=P0}"
Foreground="{Binding CPUUsage, Converter={StaticResource UsageToColorConverter}}"
Margin="10,0,0,0"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<!-- 右侧面板 - 详细信息 -->
<TabControl Grid.Column="1">
<TabItem Header="性能">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Text="CPU使用率" FontWeight="Bold" Margin="5"/>
<ProgressBar Grid.Row="1" Value="{Binding CpuUsage}" Height="20" Margin="5"/>
</Grid>
</TabItem>
<TabItem Header="内存">
<!-- 内存使用图表 -->
<views:MemoryChart DataContext="{Binding MemoryData}"/>
</TabItem>
</TabControl>
</Grid>
cs
// ViewModel实现
public class TaskManagerViewModel : ViewModelBase
{
private ObservableCollection<ProcessInfo> _processes = new ObservableCollection<ProcessInfo>();
public ObservableCollection<ProcessInfo> Processes => _processes;
private ProcessInfo _selectedProcess;
public ProcessInfo SelectedProcess
{
get => _selectedProcess;
set => SetField(ref _selectedProcess, value);
}
private double _cpuUsage;
public double CpuUsage
{
get => _cpuUsage;
set => SetField(ref _cpuUsage, value);
}
public TaskManagerViewModel()
{
// 启动后台更新
Task.Run(() => UpdateProcessesAsync());
Task.Run(() => UpdateCpuUsageAsync());
}
private async Task UpdateProcessesAsync()
{
while (true)
{
var processes = await System.Diagnostics.Process.GetProcessesAsync();
// 转换为ProcessInfo对象并更新集合
await Application.Current.Dispatcher.InvokeAsync(() =>
{
Processes.Clear();
foreach (var p in processes)
{
Processes.Add(new ProcessInfo(p));
}
});
await Task.Delay(1000);
}
}
private async Task UpdateCpuUsageAsync()
{
// CPU使用率计算逻辑...
}
}
2. 图表控件实现
cs
<!-- 自定义图表控件 -->
<UserControl x:Class="YourApp.Controls.CustomChart"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Canvas Name="ChartCanvas"/>
</Grid>
</UserControl>
// 代码后端
public partial class CustomChart : UserControl
{
public static readonly DependencyProperty DataProperty =
DependencyProperty.Register("Data", typeof(ObservableCollection<ChartDataPoint>),
typeof(CustomChart), new PropertyMetadata(null, OnDataChanged));
public ObservableCollection<ChartDataPoint> Data
{
get => (ObservableCollection<ChartDataPoint>)GetValue(DataProperty);
set => SetValue(DataProperty, value);
}
public CustomChart()
{
InitializeComponent();
DataContext = this;
}
private static void OnDataChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is CustomChart chart)
{
chart.UpdateChart();
}
}
private void UpdateChart()
{
ChartCanvas.Children.Clear();
if (Data == null || !Data.Any()) return;
var max = Data.Max(d => d.Value);
var width = ChartCanvas.ActualWidth / Math.Max(1, Data.Count);
for (int i = 0; i < Data.Count; i++)
{
var point = Data[i];
var height = (point.Value / max) * ChartCanvas.ActualHeight;
var rect = new Rectangle
{
Width = width - 1,
Height = height,
Fill = point.Color,
Margin = new Thickness(i * width, ChartCanvas.ActualHeight - height, 0, 0)
};
ChartCanvas.Children.Add(rect);
}
}
}
// 数据点类
public class ChartDataPoint
{
public double Value { get; set; }
public Color Color { get; set; }
public ChartDataPoint(double value, Color color)
{
Value = value;
Color = color;
}
}
十一、部署与打包
1. ClickOnce部署
XML
<!-- 发布设置 -->
<Project>
<PropertyGroup>
<PublishDir>\\Server\Deploy\</PublishDir>
<InstallUrl>http://server/deploy/</InstallUrl>
<ApplicationVersion>1.0.0.0</ApplicationVersion>
<MinimumRequiredVersion>1.0.0.0</MinimumRequiredVersion>
<UpdateEnabled>true</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
</PropertyGroup>
</Project>
2. MSI打包
XML
# 使用WiX工具创建MSI安装包
# 1. 安装WiX工具集
# 2. 创建.wxs项目文件
# 3. 定义产品特性
<Product Id="*" Name="YourApp" Language="1033" Version="1.0.0.0"
Manufacturer="YourCompany" UpgradeCode="PUT-GUID-HERE">
<Package InstallerVersion="500" Compressed="yes" InstallScope="perMachine"/>
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed."/>
<Feature Id="ProductFeature" Title="YourApp" Level="1">
<ComponentGroupRef Id="ProductComponents"/>
</Feature>
</Product>
<ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
<Component Id="MainExecutable">
<File Source="$(var.YourApp.TargetPath)" KeyPath="yes"/>
</Component>
</ComponentGroup>
十二、未来扩展方向
1. 跨平台支持
cs
// 使用Avalonia实现跨平台UI
public class CrossPlatformWindow : Window
{
public CrossPlatformWindow()
{
// 平台特定初始化
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
// Windows特定设置
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
// Linux特定设置
}
}
}
2. 云集成
cs
// 集成Azure服务
public class CloudService
{
private readonly HttpClient _client = new HttpClient();
public async Task UploadFileAsync(string filePath)
{
var content = new MultipartFormDataContent();
var fileContent = new ByteArrayContent(File.ReadAllBytes(filePath));
content.Add(fileContent, "file", Path.GetFileName(filePath));
var response = await _client.PostAsync("https://yourapp.azurewebsites.net/api/upload", content);
response.EnsureSuccessStatusCode();
}
}
3. AI集成
cs
// 集成ML.NET进行数据分析
public class DataAnalyzer
{
private readonly PredictionEngine<InputData, PredictionResult> _predictionEngine;
public DataAnalyzer()
{
var mlContext = new MLContext();
var pipeline = mlContext.Transforms.Concatenate("Features", "Feature1", "Feature2")
.Append(mlContext.BinaryClassification.Trainers.SdcaLogisticRegression());
var model = pipeline.Fit(mlContext.Data.LoadFromTextFile<InputData>("data.csv", hasHeader: true));
_predictionEngine = mlContext.Model.CreatePredictionEngine<InputData, PredictionResult>(model);
}
public bool Analyze(InputData data) => _predictionEngine.Predict(data).PredictedLabel;
}
通过以上高级技术和示例代码,您可以构建功能丰富、性能优越的WPF应用程序,并为未来的扩展和维护打下坚实的基础。