VersionManager
VersionManager\MainWindow.xaml.cs
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using VersionManager.Utilities;
namespace VersionManager;
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
string version = VersionHelper.GetFormattedVersion();
this.Title = $"MVVM Demo - v{version}";
}
}
VersionManager\VersionManager.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net10.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UseWPF>true</UseWPF>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
<FileVersion>1.0.0.0</FileVersion>
<Version>1.0.0</Version>
</PropertyGroup>
</Project>
VersionManager\Commands\RelayCommand.cs
using System;
using System.Windows.Input;
namespace VersionManager.Commands
{
public class RelayCommand : ICommand
{
private readonly Action _execute;
private readonly Func<bool>? _canExecute;
public RelayCommand(Action execute, Func<bool>? canExecute = null)
{
_execute = execute ?? throw new ArgumentNullException(nameof(execute));
_canExecute = canExecute;
}
public event EventHandler? CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public bool CanExecute(object? parameter)
{
return _canExecute?.Invoke() ?? true;
}
public void Execute(object? parameter)
{
_execute();
}
}
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 event EventHandler? CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public bool CanExecute(object? parameter)
{
return _canExecute?.Invoke((T)parameter!) ?? true;
}
public void Execute(object? parameter)
{
_execute((T)parameter!);
}
}
}
VersionManager\Utilities\VersionHelper.cs
using System;
using System.Reflection;
namespace VersionManager.Utilities
{
public static class VersionHelper
{
public static string GetApplicationVersion()
{
var version = Assembly.GetExecutingAssembly().GetName().Version;
return version?.ToString() ?? "1.0.0";
}
public static string GetFormattedVersion()
{
var version = Assembly.GetExecutingAssembly().GetName().Version;
if (version != null)
{
return $"{version.Major}.{version.Minor}.{version.Build}";
}
return "1.0.0";
}
}
}
VersionManager\ViewModels\MainViewModel.cs
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Input;
using VersionManager.Commands;
using VersionManager.Utilities;
namespace VersionManager.ViewModels
{
public class MainViewModel : INotifyPropertyChanged
{
private string? _inputText;
private string? _displayText;
public string InputText
{
get => _inputText ?? string.Empty;
set
{
_inputText = value;
OnPropertyChanged();
}
}
public string DisplayText
{
get => _displayText ?? "请输入内容...";
set
{
_displayText = value;
OnPropertyChanged();
}
}
public string ApplicationVersion { get; }
public ICommand UpdateDisplayCommand { get; }
public MainViewModel()
{
_inputText = string.Empty;
_displayText = "请输入内容...";
ApplicationVersion = VersionHelper.GetFormattedVersion();
UpdateDisplayCommand = new RelayCommand(UpdateDisplay);
}
private void UpdateDisplay()
{
DisplayText = InputText;
}
public event PropertyChangedEventHandler? PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
VersionManager\MainWindow.xaml
<Window x:Class="VersionManager.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:VersionManager"
xmlns:viewmodels="clr-namespace:VersionManager.ViewModels"
mc:Ignorable="d"
Title="MVVM Demo" Height="450" Width="800">
<Window.DataContext>
<viewmodels:MainViewModel />
</Window.DataContext>
<Grid Margin="20">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Margin="0,0,0,20">
<TextBlock Text="MVVM 示例 - 输入并显示文本"
FontSize="18" FontWeight="Bold" HorizontalAlignment="Center" />
<TextBlock Text="{Binding ApplicationVersion, StringFormat='版本: {0}'}"
FontSize="12" HorizontalAlignment="Center" Margin="0,5,0,0" Foreground="Gray" />
</StackPanel>
<TextBox Grid.Row="1"
Text="{Binding InputText, UpdateSourceTrigger=PropertyChanged}"
Margin="0,0,0,10"
Width="300"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Height="30"
FontSize="14"
Name="InputTextBox" />
<Button Grid.Row="2"
Content="显示文本"
Command="{Binding UpdateDisplayCommand}"
Margin="0,0,0,20"
Width="100"
Height="30"
HorizontalAlignment="Center"
FontSize="14" />
<Border Grid.Row="4"
BorderBrush="Gray"
BorderThickness="1"
Background="#F5F5F5"
CornerRadius="5"
Padding="10">
<TextBlock Text="{Binding DisplayText}"
FontSize="16"
VerticalAlignment="Center"
HorizontalAlignment="Center"
TextWrapping="Wrap" />
</Border>
</Grid>
</Window>
VersionManager\App.xaml
<Application x:Class="VersionManager.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:VersionManager"
StartupUri="MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>
VersionManager\VersionManager.sln
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.2.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VersionManager", "VersionManager.csproj", "{81BBCE8F-7189-466A-C291-B3A8DA2783D9}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{81BBCE8F-7189-466A-C291-B3A8DA2783D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{81BBCE8F-7189-466A-C291-B3A8DA2783D9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{81BBCE8F-7189-466A-C291-B3A8DA2783D9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{81BBCE8F-7189-466A-C291-B3A8DA2783D9}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {FF1DB3F9-1599-40EB-B763-0D2BC03486FD}
EndGlobalSection
EndGlobal
VersionManager\App.xaml.cs
using System.Configuration;
using System.Data;
using System.Windows;
namespace VersionManager;
public partial class App : Application
{
}
README.md_# VersionManager
一个使用 MVVM 模式实现的 WPF 应用程序示例,包含输入框、按钮和显示标签功能。
功能特性
- 输入文本框:用户可以输入文本内容
- 显示按钮:点击按钮将输入内容显示到标签上
- 显示标签:展示用户输入的文本内容
- MVVM 架构:采用 Model-View-ViewModel 设计模式
开发环境要求
- .NET 10.0 或更高版本
- Visual Studio 2022 或 Visual Studio Code
- C# 10.0 或更高版本
项目结构
VersionManager/
├── Commands/
│ └── RelayCommand.cs # 实现ICommand接口的命令类
├── ViewModels/
│ └── MainViewModel.cs # 主视图模型,处理业务逻辑
├── App.xaml # 应用程序启动配置
├── App.xaml.cs # 应用程序逻辑
├── MainWindow.xaml # 主窗口界面
├── MainWindow.xaml.cs # 主窗口逻辑
└── README.md # 项目说明文档
发布脚本
发布为独立应用(包含运行时)
# 发布到指定文件夹(包含所有运行时)
dotnet publish -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true -p:IncludeAllContentForSelfExtract=true -o ./publish/standalone
发布为框架依赖应用(需要目标机器安装.NET 运行时)
# 发布为框架依赖应用
dotnet publish -c Release -r win-x64 --self-contained false -o ./publish/framework-dependent
发布为单文件应用
# 发布为单文件可执行程序
dotnet publish -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true -o ./publish/single-file
发布时指定版本号
# 发布时指定版本号(临时覆盖项目文件中的版本)
dotnet publish -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:Version=1.3.0 -p:AssemblyVersion=1.3.0.0 -p:FileVersion=1.3.0.0 -o ./publish/v1.3.0
dotnet publish -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true -p:AssemblyVersion=1.4.0.0 -o ./publish/v1.4.0
dotnet publish -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true -p:AssemblyVersion=1.5.1.0 -o ./publish/v1.5.0
dotnet publish -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true -p:AssemblyVersion=1.5.1.2 -o ./publish/v1.5.0
dotnet publish -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true -p:AssemblyVersion=1.5.3 -o ./publish/v1.5.3
dotnet publish -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true -p:AssemblyVersion=1.4.1.0 -o ./publish/v1.4.1
不同平台发布
# Windows x64
dotnet publish -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -o ./publish/win-x64
# Windows x86
dotnet publish -c Release -r win-x86 --self-contained true -p:PublishSingleFile=true -o ./publish/win-x86
# Linux x64
dotnet publish -c Release -r linux-x64 --self-contained true -p:PublishSingleFile=true -o ./publish/linux-x64
# macOS x64
dotnet publish -c Release -r osx-x64 --self-contained true -p:PublishSingleFile=true -o ./publish/mac-x64
构建时指定版本号
# 构建时指定版本号
dotnet build -p:Version=1.2.0 -p:AssemblyVersion=1.2.0.0 -p:FileVersion=1.2.0.0
# 发布时指定版本号
dotnet publish -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:Version=1.2.0 -o ./publish/versioned-app
构建和运行
调试模式运行
# 恢复依赖
dotnet restore
# 构建项目
dotnet build
# 运行应用
dotnet run
发布并运行
# 发布应用
dotnet publish -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -o ./publish
# 运行发布的应用(Windows)
./publish/VersionManager.exe
项目配置
当前项目配置为:
- 目标框架:net10.0-windows
- 输出类型:WinExe
- 用户界面:WPF
- 架构模式:MVVM
部署说明
- 如果目标机器已安装.NET 运行时,可使用框架依赖发布方式
- 如果目标机器未安装.NET 运行时,需使用自包含发布方式
- 单文件发布方式便于分发,但启动时间可能稍长
- 发布后的应用可在对应平台上直接运行
版本历史
- v1.0.0: MVVM 架构实现,包含基本输入输出功能
- v1.0.1: 添加版本号显示功能,可在界面上显示应用程序版本
Version.md_# .NET 项目中的版本号属性说明
在 .NET 项目中,有三个主要的版本号属性:AssemblyVersion、FileVersion 和 Version。它们各自有不同的用途和影响。
AssemblyVersion
AssemblyVersion 是程序集的版本号,用于运行时识别程序集。这个版本号:
- 用于程序集加载和绑定
- 影响程序集的强名称签名
- 在 GAC(全局程序集缓存)中用于区分程序集
- 当引用程序集时,如果版本不匹配可能会导致运行时错误
- 通常只在重大更新时才更改,以保持向后兼容性
示例
<AssemblyVersion>1.0.0.0</AssemblyVersion>
FileVersion
FileVersion 是文件的实际版本号,显示在操作系统的文件属性中。这个版本号:
- 用于文件系统级别的版本控制
- 显示在 Windows 文件资源管理器的文件属性中
- 用于 Windows 安装程序的版本比较
- 可以在不破坏程序集绑定的情况下更新
示例
<FileVersion>1.0.0.2304</FileVersion>
Version (PackageVersion)
Version(或 PackageVersion)是 NuGet 包的版本号,用于包管理。这个版本号:
- 用于 NuGet 包的版本控制
- 决定包在 NuGet 仓库中的标识
- 影响包的依赖关系管理
- 也是应用程序显示给用户的版本号(当使用
Assembly.GetExecutingAssembly().GetName().Version时)
示例
<Version>1.0.0</Version>
三者之间的关系
在实际项目中,这三个版本号可以设置为相同或不同,具体取决于项目需求:
- 如果项目不作为 NuGet 包发布,
Version主要影响应用程序内部的版本查询 AssemblyVersion的变化会影响程序集的兼容性FileVersion用于操作系统层面的版本识别
在当前项目中的应用
在 VersionManager 项目中,我们设置了三个版本号:
<AssemblyVersion>1.0.0.0</AssemblyVersion>
<FileVersion>1.0.0.0</FileVersion>
<Version>1.0.0</Version>
当我们使用 VersionHelper.GetApplicationVersion() 时,实际获取的是 AssemblyVersion,因为 Assembly.GetExecutingAssembly().GetName().Version 返回的是程序集版本。
版本号格式
所有版本号通常遵循语义化版本控制(SemVer)格式:主版本号.次版本号.修订号.构建号
- 主版本号:重大更新,可能包含不兼容的 API 变更
- 次版本号:向后兼容的功能新增
- 修订版本号:向后兼容的问题修正
- 构建号:内部构建版本(可选)
最佳实践
- 保持
AssemblyVersion稳定以确保兼容性 - 频繁更新
FileVersion以反映构建版本 - 根据发布周期更新
Version以反映功能更新 - 在生产环境中,通常将三个版本号保持一致以避免混淆
浙公网安备 33010602011771号