Windows Presentation Foundation (WPF) 是一个用于构建 Windows 应用程序的强大框架。它支持丰富的用户界面和数据绑定,采用了 MVVM(Model-View-ViewModel)设计模式,使得应用程序的结构更加清晰和易于维护。本文将详细解析一个标准 WPF 项目的基础结构,并提供完整的示例代码。
一个典型的 WPF 项目结构如下所示:
C#MyWpfApp/
├── Properties/
│ └── AssemblyInfo.cs # 程序集信息
├── References/ # 项目引用
├── App.xaml # 应用程序入口和全局资源
├── App.xaml.cs # 应用程序代码隐藏
├── MainWindow.xaml # 主窗口XAML
└── MainWindow.xaml.cs # 主窗口代码隐藏
├── Assets/ # 资源文件
│ ├── Images/ # 图片资源
│ ├── Icons/ # 图标资源
│ └── Styles/ # 样式资源
├── Models/ # 数据模型
├── ViewModels/ # 视图模型
├── Views/ # 视图
├── Services/ # 服务层
├── Helpers/ # 辅助类
├── Controls/ # 自定义控件
└── Converters/ # 值转换器
INotifyPropertyChanged
接口以支持数据绑定。WPF 应用程序通常采用 MVVM 设计模式。以下是 MVVM 的基本组成部分:
C#using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace AppWpf003.Helpers
{
public class RelayCommand<T> : ICommand
{
private readonly Action<T> _execute;
private readonly Predicate<T> _canExecute;
public RelayCommand(Action<T> execute, Predicate<T> canExecute = null)
{
_execute = execute ?? throw new ArgumentNullException(nameof(execute));
_canExecute = canExecute;
}
public bool CanExecute(object parameter) => _canExecute == null || _canExecute((T)parameter);
public void Execute(object parameter) => _execute((T)parameter);
public event EventHandler CanExecuteChanged
{
add => CommandManager.RequerySuggested += value;
remove => CommandManager.RequerySuggested -= value;
}
}
}
C#using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AppWpf003.Models
{
public class TaskModel
{
public string TaskName { get; set; }
}
}
C#using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AppWpf003.ViewModels
{
public class BaseViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
C#using AppWpf003.Helpers;
using AppWpf003.Models;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace AppWpf003.ViewModels
{
public class MainViewModel : BaseViewModel
{
public ObservableCollection<TaskModel> Tasks { get; set; }
public ICommand AddTaskCommand { get; set; }
public ICommand DeleteTaskCommand { get; set; }
private string _newTaskName;
public string NewTaskName
{
get { return _newTaskName; }
set
{
_newTaskName = value;
OnPropertyChanged(nameof(NewTaskName));
}
}
public MainViewModel()
{
Tasks = new ObservableCollection<TaskModel>();
AddTaskCommand = new RelayCommand<object>(AddTask);
DeleteTaskCommand = new RelayCommand<TaskModel>(DeleteTask);
}
private void AddTask(object parameter)
{
if (!string.IsNullOrEmpty(NewTaskName))
{
Tasks.Add(new TaskModel { TaskName = NewTaskName });
NewTaskName = string.Empty; // Clear input
}
}
private void DeleteTask(TaskModel task)
{
if (Tasks.Contains(task))
{
Tasks.Remove(task);
}
}
}
}
C#<Window x:Class="AppWpf003.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:AppWpf003.ViewModels"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<!-- 引入 Styles -->
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Assets/Styles/Colors.xaml"/>
<ResourceDictionary Source="Assets/Styles/TextStyles.xaml"/>
<ResourceDictionary Source="Assets/Styles/Buttons.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
<Grid>
<StackPanel Margin="10">
<TextBox Width="300" Margin="0,0,0,10" Text="{Binding NewTaskName, UpdateSourceTrigger=PropertyChanged}"/>
<Button Content="Add Task" Command="{Binding AddTaskCommand}" Width="100" Margin="0,0,0,10" Style="{StaticResource DefaultButtonStyle}"/>
<ListBox x:Name="TaskList" ItemsSource="{Binding Tasks}" SelectedItem="{Binding SelectedTask}" DisplayMemberPath="TaskName" Margin="0,0,0,10"/>
<Button Content="Delete Task" Command="{Binding DeleteTaskCommand}" CommandParameter="{Binding SelectedItem, ElementName=TaskList}" Width="100"/>
</StackPanel>
</Grid>
</Window>
通过遵循上述结构和最佳实践,可以创建一个易于维护、扩展和测试的 WPF 应用程序。MVVM 模式的使用使得代码的组织更加清晰,便于团队协作和后期维护。希望本文能为您在 WPF 开发中提供有价值的参考。
本文作者:rick
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!