怪奇物语

怪奇物语

首页 新随笔 联系 管理

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

部署说明

  1. 如果目标机器已安装.NET 运行时,可使用框架依赖发布方式
  2. 如果目标机器未安装.NET 运行时,需使用自包含发布方式
  3. 单文件发布方式便于分发,但启动时间可能稍长
  4. 发布后的应用可在对应平台上直接运行

版本历史

  • v1.0.0: MVVM 架构实现,包含基本输入输出功能
  • v1.0.1: 添加版本号显示功能,可在界面上显示应用程序版本

Version.md_# .NET 项目中的版本号属性说明

在 .NET 项目中,有三个主要的版本号属性:AssemblyVersionFileVersionVersion。它们各自有不同的用途和影响。

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 变更
  • 次版本号:向后兼容的功能新增
  • 修订版本号:向后兼容的问题修正
  • 构建号:内部构建版本(可选)

最佳实践

  1. 保持 AssemblyVersion 稳定以确保兼容性
  2. 频繁更新 FileVersion 以反映构建版本
  3. 根据发布周期更新 Version 以反映功能更新
  4. 在生产环境中,通常将三个版本号保持一致以避免混淆
posted on 2025-12-30 08:00  超级无敌美少男战士  阅读(1)  评论(0)    收藏  举报