├── .gitattributes
├── .github
└── workflows
│ ├── dotnet-build.yml
│ └── nuget-push.yml
├── .gitignore
├── Directory.Build.props
├── README.md
├── Walterlv.Packages.sln
├── build
└── Version.props
├── docs
├── Packages
│ ├── Walterlv.Logger
│ │ └── README.md
│ └── Walterlv.NullableAttributes
│ │ └── README.md
└── Tools
│ └── Walterlv.CodeAnalysis.Analyzers
│ └── README.md
├── samples
└── Walterlv.Windows.Sample
│ ├── App.config
│ ├── App.xaml
│ ├── App.xaml.cs
│ ├── MainViewModel.cs
│ ├── MainWindow.xaml
│ ├── MainWindow.xaml.cs
│ ├── Properties
│ └── App.manifest
│ ├── ViewModels
│ ├── FluentViewModel.cs
│ └── HomeViewModel.cs
│ ├── Views
│ ├── FluentPage.xaml
│ ├── FluentPage.xaml.cs
│ ├── HomePage.xaml
│ └── HomePage.xaml.cs
│ └── Walterlv.Windows.Sample.csproj
├── src
├── Analyzers
│ └── Walterlv.CodeAnalysis.Analyzers
│ │ ├── Analyzers
│ │ └── AutoPropertyAnalyzer.cs
│ │ ├── CodeFixes
│ │ ├── AutoPropertyToAttachedPropertyCodeFixProvider.cs
│ │ ├── AutoPropertyToDependencyPropertyCodeFixProvider.cs
│ │ ├── AutoPropertyToNotificationPropertyCodeFixProvider.cs
│ │ └── AutoPropertyToOtherCodeFixProvider.cs
│ │ ├── DiagnosticIds.cs
│ │ ├── DiagnosticUrls.cs
│ │ ├── Properties
│ │ ├── LocalizableStrings.cs
│ │ ├── Resources.Designer.cs
│ │ ├── Resources.resx
│ │ └── Resources.zh-CN.resx
│ │ └── Walterlv.CodeAnalysis.Analyzers.csproj
├── Directory.Build.props
├── Directory.Build.targets
├── Frameworks
│ └── Walterlv.Windows.Framework
│ │ ├── Walterlv.Windows.Framework (Package)
│ │ └── Walterlv.Windows.Framework (Package).csproj
│ │ ├── Walterlv.Windows.Framework.WinUI
│ │ └── Walterlv.Windows.Framework.WinUI.csproj
│ │ └── Walterlv.Windows.Framework.Wpf
│ │ ├── ComponentModel
│ │ └── BindableObject.cs
│ │ ├── Walterlv.Windows.Framework.Wpf.csproj
│ │ └── Windows
│ │ ├── Input
│ │ ├── ActionCommand.cs
│ │ └── ActionCommand`1.cs
│ │ └── Navigating
│ │ ├── INavigationView.cs
│ │ ├── INavigationViewModel.cs
│ │ ├── NavigationItem.cs
│ │ ├── NavigationItemAttribute.cs
│ │ ├── NavigationView.cs
│ │ └── NavigationViewModel.cs
├── Themes
│ └── Walterlv.Themes.FluentDesign
│ │ ├── Controls
│ │ └── ClientAreaBorder.cs
│ │ ├── Converters
│ │ └── ColorToBrushConverter.cs
│ │ ├── Core
│ │ └── Dpi.cs
│ │ ├── Effects
│ │ ├── AccentCompositionBorder.cs
│ │ ├── RevealBorderBrushExtension.cs
│ │ ├── TiltEffect2D.cs
│ │ └── WindowAccentCompositor.cs
│ │ ├── Themes
│ │ ├── Window.Universal.xaml
│ │ └── Window.Universal.xaml.cs
│ │ └── Walterlv.Themes.FluentDesign.csproj
├── Utils
│ ├── Walterlv.Collections
│ │ ├── CartesianProduct.cs
│ │ ├── Concurrent
│ │ │ ├── ObservableConcurrentBag.cs
│ │ │ ├── ReadonlyObservableBag.cs
│ │ │ └── ReadonlyObservableBagExtensions.cs
│ │ ├── Generic
│ │ │ └── WeakCollection.cs
│ │ ├── Threading
│ │ │ └── AsyncQueue.cs
│ │ └── Walterlv.Collections.csproj
│ ├── Walterlv.Console
│ │ ├── ConsoleTables
│ │ │ ├── ConsoleTableBuilder.cs
│ │ │ └── ConsoleTableColumnDefinition.cs
│ │ ├── Utils
│ │ │ └── ConsoleStringExtensions.cs
│ │ └── Walterlv.Console.csproj
│ ├── Walterlv.Environment
│ │ ├── NdpInfo.cs
│ │ └── Walterlv.Environment.csproj
│ ├── Walterlv.IO.PackageManagement
│ │ ├── Core
│ │ │ └── JunctionPoint.cs
│ │ ├── DirectoryOverwriteStrategy.cs
│ │ ├── FileMergeResolvingInfo.cs
│ │ ├── FileMergeStrategy.cs
│ │ ├── IOResult.cs
│ │ ├── PackageDirectory.cs
│ │ ├── VersionedPackageDirectory.cs
│ │ └── Walterlv.IO.PackageManagement.csproj
│ ├── Walterlv.IO
│ │ ├── FileNameHelper.cs
│ │ └── Walterlv.IO.csproj
│ ├── Walterlv.Logger
│ │ ├── Composition
│ │ │ └── CompositeLogger.cs
│ │ ├── Core
│ │ │ ├── ActionLogger.cs
│ │ │ ├── AsyncOutputLogger.AsyncQueue.cs
│ │ │ ├── AsyncOutputLogger.cs
│ │ │ ├── LogContext.cs
│ │ │ ├── OutputLogger.cs
│ │ │ └── TaskFuncLogger.cs
│ │ ├── ILogger.cs
│ │ ├── IO
│ │ │ ├── TextFileLogger.cs
│ │ │ └── TextFileLoggerExtensions.cs
│ │ ├── LogLevel.cs
│ │ ├── Markdown
│ │ │ ├── IMarkdownDataTemplate.cs
│ │ │ ├── MarkdownDataTemplate.cs
│ │ │ ├── MarkdownLogFormatter.cs
│ │ │ └── MarkdownLogger.cs
│ │ ├── Standard
│ │ │ ├── AsyncConsoleLogger.cs
│ │ │ ├── ConsoleLogWriter.cs
│ │ │ └── ConsoleLogger.cs
│ │ └── Walterlv.Logger.csproj
│ ├── Walterlv.WeakEvents
│ │ ├── Walterlv.WeakEvents.csproj
│ │ ├── WeakEvent.cs
│ │ └── WeakEventRelay.cs
│ ├── Walterlv.Web
│ │ ├── Core
│ │ │ └── QueryString.cs
│ │ └── Walterlv.Web.csproj
│ ├── Walterlv.Win32
│ │ ├── RegistryScript.cs
│ │ ├── Walterlv.Win32.csproj
│ │ └── WindowEnumerator.cs
│ ├── Walterlv.Windows.Interop
│ │ ├── Interop
│ │ │ ├── Win32WindowEventArgs.cs
│ │ │ ├── WindowWrapper.cs
│ │ │ └── WpfWin32WindowWrapper.cs
│ │ ├── Media
│ │ │ └── VisualScalingExtensions.cs
│ │ └── Walterlv.Windows.Interop.csproj
│ └── Walterlv.Windows
│ │ ├── Media
│ │ ├── VisualTreeExtensions.cs
│ │ └── VisualTreeSearchConditions.cs
│ │ └── Walterlv.Windows.csproj
└── Walterlv.Packages.snk
└── tests
├── Walterlv.Packages.Performance
├── Program.cs
└── Walterlv.Packages.Performance.csproj
└── Walterlv.Packages.Tests
├── Collections
├── CartesianProductTests.cs
└── Generic
│ └── WeakCollectionTests.cs
├── Logging
└── IO
│ ├── AsyncOutputLoggerTest.cs
│ └── TextFileLoggerTests.cs
└── Walterlv.Packages.Tests.csproj
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.github/workflows/dotnet-build.yml:
--------------------------------------------------------------------------------
1 | name: .NET Build & Test
2 |
3 | on:
4 | pull_request:
5 | branches: [ master ]
6 |
7 | jobs:
8 | build:
9 | strategy:
10 | matrix:
11 | configuration: [ Debug, Release ]
12 | runs-on: windows-latest
13 | steps:
14 |
15 | - name: Checkout
16 | uses: actions/checkout@v2
17 |
18 | - name: Setup
19 | uses: actions/setup-dotnet@v1
20 | with:
21 | dotnet-version: |
22 | 8.0.x
23 |
24 | - name: Add msbuild to PATH
25 | uses: microsoft/setup-msbuild@v1.0.2
26 |
27 | - name: Build the solution
28 | run: msbuild /p:Configuration=$env:Configuration -restore
29 | env:
30 | Configuration: ${{ matrix.configuration }}
31 |
32 | - name: Test
33 | run: dotnet test --configuration $env:Configuration --no-build
34 | env:
35 | Configuration: ${{ matrix.configuration }}
36 |
--------------------------------------------------------------------------------
/.github/workflows/nuget-push.yml:
--------------------------------------------------------------------------------
1 | name: NuGet Push
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 |
7 | jobs:
8 | build:
9 | runs-on: windows-latest
10 | steps:
11 |
12 | - name: Checkout
13 | uses: actions/checkout@v2
14 |
15 | - name: Setup
16 | uses: actions/setup-dotnet@v1
17 | with:
18 | dotnet-version: |
19 | 8.0.x
20 |
21 | - name: Add msbuild to PATH
22 | uses: microsoft/setup-msbuild@v1.0.2
23 |
24 | - name: Build the solution
25 | run: msbuild /p:Configuration=Release -restore
26 |
27 | - name: Push
28 | run: dotnet nuget push .\artifacts\package\release\*.nupkg --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NuGetAPIKey }} --skip-duplicate --no-symbols 1
29 |
--------------------------------------------------------------------------------
/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | latest
8 | enable
9 | $(MSBuildThisFileDirectory)artifacts
10 | $(MSBuildThisFileDirectory)
11 |
12 |
13 |
14 |
17 | $(NoWarn);NETSDK1138
18 |
19 |
20 |
21 |
22 | walterlv
23 | walterlv
24 | Walterlv.Packages
25 | Copyright (c) 2019-2021 dotnet campus
26 | git
27 | https://github.com/walterlv/Walterlv.Packages.git
28 | https://github.com/walterlv/Walterlv.Packages
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/build/Version.props:
--------------------------------------------------------------------------------
1 |
2 |
3 | 7.10.1
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/Packages/Walterlv.Logger/README.md:
--------------------------------------------------------------------------------
1 | # Walterlv.Logger
2 |
--------------------------------------------------------------------------------
/docs/Packages/Walterlv.NullableAttributes/README.md:
--------------------------------------------------------------------------------
1 | # Walterlv.NullableAttributes
2 |
3 | ## NuGet 包
4 |
5 | - 如果你不在意为你的项目引入一个额外的依赖库,那么可以安装 NuGet 包 Walterlv.NullableAttributes [](https://www.nuget.org/packages/Walterlv.NullableAttributes/)。
6 | - 如果你要求你的项目不能引入新的依赖,必须要将相关类型直接嵌入到你的目标程序集中,那么请安装 NuGet 包 Walterlv.NullableAttributes.Source [](https://www.nuget.org/packages/Walterlv.NullableAttributes.Source/)。
7 |
8 | 因为 .NET Core 3.0 开始,已经内置支持了本包所带的所有类型,所以在 .NET Core 3.0 以上的项目安装此包后是不会引入任何依赖,也不会嵌入任何代码的。而 .NET Framework 4.8 及以下,.NET Standard 2.1 及以下,.NET Core 2.1 及以下的项目安装此包时,则会引用所需的类型,或者嵌入所需类型的源码。
9 |
10 | 你也不用担心跨框架引用项目时,会不会导致类型多余或者缺失。本包的引用版本和源码版本都已经做好了跨版本引用的处理。
11 |
12 | ## 介绍可空引用类型
13 |
14 | C# 8.0 引入了可空引用类型,你可以通过 `?` 为字段、属性、方法参数、返回值等添加是否可为 null 的特性。
15 |
16 | 但是如果你真的在把你原有的旧项目迁移到可空类型的时候,你就会发现情况远比你想象当中复杂,因为你写的代码可能只在部分情况下可空,部分情况下不可空;或者传入空时才可为空,传入非空时则不可为空。
17 |
18 | 在开始迁移你的项目之前,你可能需要了解如何开启项目的可空类型支持:
19 |
20 | - [C# 8.0 如何在项目中开启可空引用类型的支持 - walterlv](https://blog.walterlv.com/post/how-to-enable-nullable-reference-types)
21 |
22 | 可空引用类型是 C# 8.0 带来的新特性。
23 |
24 | 你可能会好奇,C# 语言的可空特性为什么在编译成类库之后,依然可以被引用它的程序集识别。也许你可以理解为有什么特性 `Attribute` 标记了字段、属性、方法参数、返回值的可空特性,于是可空特性就被编译到程序集中了。
25 |
26 | 确实,可空特性是通过 `NullableAttribute` 和 `NullableContextAttribute` 这两个特性标记的。
27 |
28 | 但你是否好奇,即使在古老的 .NET Framework 4.5 或者 .NET Standard 2.0 中开发的时候,你也可以编译出支持可空信息的程序集出来。这些古老的框架中没有这些新出来的类型,为什么也可以携带类型的可空特性呢?
29 |
30 | 实际上反编译一下编译出来的程序集就能立刻看到结果了。
31 |
32 | 看下图,在早期版本的 .NET 框架中,可空特性实际上是被编译到程序集里面,作为 `internal` 的 `Attribute` 类型了。
33 |
34 | 
35 |
36 | 所以,放心使用可空类型吧!旧版本的框架也是可以用的。
37 |
38 | ## 本包的功能:更灵活控制的可空特性
39 |
40 | 阻碍你将老项目迁移到可空类型的原因,可能还有你原来代码逻辑的问题。因为有些情况下你无法完完全全将类型迁移到可空。
41 |
42 | 例如:
43 |
44 | 1. 有些时候你不得不为非空的类型赋值为 `null` 或者获取可空类型时你能确保此时一定不为 `null`(待会儿我会解释到底是什么情况);
45 | 1. 一个方法,可能这种情况下返回的是 `null` 那种情况下返回的是非 `null`;
46 | 1. 可能调用者传入 `null` 的时候才返回 `null`,传入非 `null` 的时候返回非 `null`。
47 |
48 | 为了解决这些情况,C# 8.0 还同时引入了下面这些 `Attribute`:
49 |
50 | - `AllowNull`: 标记一个不可空的输入实际上是可以传入 null 的。
51 | - `DisallowNull`: 标记一个可空的输入实际上不应该传入 null。
52 | - `MaybeNull`: 标记一个非空的返回值实际上可能会返回 null,返回值包括输出参数。
53 | - `NotNull`: 标记一个可空的返回值实际上是不可能为 null 的。
54 | - `MaybeNullWhen`: 当返回指定的 true/false 时某个输出参数才可能为 null,而返回相反的值时那个输出参数则不可为 null。
55 | - `NotNullWhen`: 当返回指定的 true/false 时,某个输出参数不可为 null,而返回相反的值时那个输出参数则可能为 null。
56 | - `NotNullIfNotNull`: 指定的参数传入 null 时才可能返回 null,指定的参数传入非 null 时就不可能返回 null。
57 | - `DoesNotReturn`: 指定一个方法是不可能返回的。
58 | - `DoesNotReturnIf`: 在方法的输入参数上指定一个条件,当这个参数传入了指定的 true/false 时方法不可能返回。
59 |
60 | 想必有了这些描述后,你在具体遇到问题的时候应该能知道选用那个特性。但单单看到这些特性的时候你可能不一定知道什么情况下会用得着,于是我可以为你举一些典型的例子。
61 |
62 | ### 输入:`AllowNull`
63 |
64 | 设想一下你需要写一个属性:
65 |
66 | ```csharp
67 | public string Text
68 | {
69 | get => GetValue() ?? "";
70 | set => SetValue(value ?? "");
71 | }
72 | ```
73 |
74 | 当你获取这个属性的值的时候,你一定不会获取到 `null`,因为我们在 `get` 里面指定了非 `null` 的默认值。然而我是允许你设置 `null` 到这个属性的,因为我处理好了 `null` 的情况。
75 |
76 | 于是,请为这个属性加上 `AllowNull`。这样,获取此属性的时候会得到非 `null` 的值,而设置的时候却可以设置成 `null`。
77 |
78 | ```diff
79 | ++ [AllowNull]
80 | public string Text
81 | {
82 | get => GetValue() ?? "";
83 | set => SetValue(value ?? "");
84 | }
85 | ```
86 |
87 | ### 输入:`DisallowNull`
88 |
89 | 与以上场景相反的一个场景:
90 |
91 | ```csharp
92 | private string? _text;
93 |
94 | public string? Text
95 | {
96 | get => _text;
97 | set => _text = value ?? throw new ArgumentNullException(nameof(value), "不允许将这个值设置为 null");
98 | }
99 | ```
100 |
101 | 当你获取这个属性的时候,这个属性可能还没有初始化,于是我们获取到 `null`。然而我却并不允许你将这个属性赋值为 `null`,因为这是个不合理的值。
102 |
103 | 于是,请为这个属性加上 `DisallowNull`。这样,获取此属性的时候会得到可能为 `null` 的值,而设置的时候却不允许为 `null`。
104 |
105 | ### 输出:`MaybeNull`
106 |
107 | 如果你有尝试过迁移代码到可空类型,基本上一定会遇到泛型方法的迁移问题:
108 |
109 | ```csharp
110 | public T Find(int index)
111 | {
112 | }
113 | ```
114 |
115 | 比如以上这个方法,找到了就返回找到的值,找不到就返回 `T` 的默认值。那么问题来了,`T` 没有指定这是值类型还是引用类型。
116 |
117 | 如果 `T` 是引用类型,那么默认值 `default(T)` 就会引入 `null`。但是泛型 `T` 并没有写成 `T?`,因此它是不可为 `null` 的。然而值类型和引用类型的 `T?` 代表的是不同的含义。这种矛盾应该怎么办?
118 |
119 | 这个时候,请给返回值标记 `MaybeNull`:
120 |
121 | ```diff
122 | ++ [return: MaybeNull]
123 | public T Find(int index)
124 | {
125 | }
126 | ```
127 |
128 | 这表示此方法应该返回一个不可为 `null` 的类型,但在某些情况下可能会返回 `null`。
129 |
130 | 实际上这样的写法并没有从本质上解决掉泛型 `T` 的问题,不过可以用来给旧项目迁移时用来兼容 API 使用。
131 |
132 | 如果你可以不用考虑 API 的兼容性,那么可以使用新的泛型契约 `where T : notnull`。
133 |
134 | ```csharp
135 | public T Find(int index) where T : notnull
136 | {
137 | }
138 | ```
139 |
140 | ### 输出:`NotNull`
141 |
142 | 设想你有一个方法,方法参数是可以传入 `null` 的:
143 |
144 | ```csharp
145 | public void EnsureInitialized(ref string? text)
146 | {
147 | }
148 | ```
149 |
150 | 然而这个方法的语义是确保此字段初始化。于是可以传入 `null` 但不会返回 `null` 的。这个时候请标记 `NotNull`:
151 |
152 | ```diff
153 | -- public void EnsureInitialized(ref string? text)
154 | ++ public void EnsureInitialized([NotNull] ref string? text)
155 | {
156 | }
157 | ```
158 |
159 | ### `NotNullWhen`, `MaybeNullWhen`
160 |
161 | `string.IsNullOrEmpty` 的实现就使用到了 `NotNullWhen`:
162 |
163 | ```csharp
164 | bool IsNullOrEmpty([NotNullWhen(false)] string? value);
165 | ```
166 |
167 | 它表示当返回 `false` 的时候,`value` 参数是不可为 `null` 的。
168 |
169 | 这样,你在这个方法返回的 `false` 判断分支里面,是不需要对变量进行判空的。
170 |
171 | 当然,更典型的还有 TryDo 模式。比如下面是 `Version` 类的 `TryParse`:
172 |
173 | ```csharp
174 | bool TryParse(string? input, [NotNullWhen(true)] out Version? result)
175 | ```
176 |
177 | 当返回 `true` 的时候,`result` 一定不为 `null`。
178 |
179 | ### `NotNullIfNotNull`
180 |
181 | 典型的情况比如指定默认值:
182 |
183 | ```csharp
184 | [return: NotNullIfNotNull("defaultValue")]
185 | public string? GetValue(string key, string? defaultValue)
186 | {
187 | }
188 | ```
189 |
190 | 这段代码里面,如果指定的默认值(`defaultValue`)是 `null` 那么返回值也就是 `null`;而如果指定的默认值是非 `null`,那么返回值也就不可为 `null` 了。
191 |
--------------------------------------------------------------------------------
/docs/Tools/Walterlv.CodeAnalysis.Analyzers/README.md:
--------------------------------------------------------------------------------
1 | # Walterlv.CodeAnalysis.Analyzers
2 |
--------------------------------------------------------------------------------
/samples/Walterlv.Windows.Sample/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/samples/Walterlv.Windows.Sample/App.xaml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 | #1570a6
11 | #3396cf
12 | #065280
13 | White
14 | #999999
15 | #232323
16 | #323232
17 | #262526
18 | #323232
19 | #3f3f42
20 | #6f6f73
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/samples/Walterlv.Windows.Sample/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Configuration;
4 | using System.Data;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 | using System.Windows;
8 |
9 | namespace Walterlv.Windows.Sample
10 | {
11 | ///
12 | /// Interaction logic for App.xaml
13 | ///
14 | public partial class App : Application
15 | {
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/samples/Walterlv.Windows.Sample/MainViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.ObjectModel;
2 | using Walterlv.ComponentModel;
3 | using Walterlv.Windows.Navigating;
4 | using Walterlv.Windows.Sample.ViewModels;
5 | using Walterlv.Windows.Sample.Views;
6 |
7 | namespace Walterlv.Windows.Sample
8 | {
9 | public class MainViewModel : BindableObject
10 | {
11 | public ObservableCollection PageItems { get; } = new ObservableCollection
12 | {
13 | NavigationItem.Combine("主页"),
14 | NavigationItem.Combine("Fluent 主题"),
15 | };
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/samples/Walterlv.Windows.Sample/MainWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Data;
9 | using System.Windows.Documents;
10 | using System.Windows.Input;
11 | using System.Windows.Interop;
12 | using System.Windows.Media;
13 | using System.Windows.Media.Imaging;
14 | using System.Windows.Navigation;
15 | using System.Windows.Shapes;
16 | using Walterlv.Windows.Effects;
17 | using Walterlv.Windows.Interop;
18 | using Walterlv.Windows.Sample.Views;
19 |
20 | namespace Walterlv.Windows.Sample
21 | {
22 | public partial class MainWindow : Window
23 | {
24 | public MainWindow()
25 | {
26 | InitializeComponent();
27 | Loaded += OnLoaded;
28 | }
29 |
30 | private async void OnLoaded(object sender, RoutedEventArgs e)
31 | {
32 | //var blur = new WindowAccentCompositor(this);
33 | //blur.Color = Color.FromArgb(0x3f, 0x18, 0xa0, 0x5e);
34 | //blur.IsEnabled = true;
35 |
36 | var childWindow = new Window
37 | {
38 | Content = new FluentPage(),
39 | };
40 | var handle = new WindowInteropHelper(childWindow).EnsureHandle();
41 | var wr = new WindowWrapper(handle);
42 | childWindow.Show();
43 | TestLayer.Child = wr;
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/samples/Walterlv.Windows.Sample/Properties/App.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | -->
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
52 | PerMonitorV2
53 | true
54 |
55 |
56 |
57 |
58 |
59 |
60 |
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/samples/Walterlv.Windows.Sample/ViewModels/FluentViewModel.cs:
--------------------------------------------------------------------------------
1 | using Walterlv.ComponentModel;
2 |
3 | namespace Walterlv.Windows.Sample.ViewModels
4 | {
5 | public class FluentViewModel : BindableObject
6 | {
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/samples/Walterlv.Windows.Sample/ViewModels/HomeViewModel.cs:
--------------------------------------------------------------------------------
1 | using Walterlv.ComponentModel;
2 |
3 | namespace Walterlv.Windows.Sample.ViewModels
4 | {
5 | public class HomeViewModel : BindableObject
6 | {
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/samples/Walterlv.Windows.Sample/Views/FluentPage.xaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/samples/Walterlv.Windows.Sample/Views/FluentPage.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Data;
9 | using System.Windows.Documents;
10 | using System.Windows.Input;
11 | using System.Windows.Media;
12 | using System.Windows.Media.Imaging;
13 | using System.Windows.Navigation;
14 | using System.Windows.Shapes;
15 |
16 | namespace Walterlv.Windows.Sample.Views
17 | {
18 | internal partial class FluentPage : UserControl
19 | {
20 | public FluentPage()
21 | {
22 | InitializeComponent();
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/samples/Walterlv.Windows.Sample/Views/HomePage.xaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/samples/Walterlv.Windows.Sample/Views/HomePage.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Data;
9 | using System.Windows.Documents;
10 | using System.Windows.Input;
11 | using System.Windows.Media;
12 | using System.Windows.Media.Imaging;
13 | using System.Windows.Navigation;
14 | using System.Windows.Shapes;
15 |
16 | namespace Walterlv.Windows.Sample.Views
17 | {
18 | internal partial class HomePage : UserControl
19 | {
20 | public HomePage()
21 | {
22 | InitializeComponent();
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/samples/Walterlv.Windows.Sample/Walterlv.Windows.Sample.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | WinExe
5 | net6.0-windows;net48
6 | true
7 | Properties\App.manifest
8 |
9 |
10 |
11 |
12 |
13 | all
14 | runtime; build; native; contentfiles; analyzers; buildtransitive
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/src/Analyzers/Walterlv.CodeAnalysis.Analyzers/Analyzers/AutoPropertyAnalyzer.cs:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/walterlv/Walterlv.Packages/54b5462e55e196c415e2139faf53f26f948070e4/src/Analyzers/Walterlv.CodeAnalysis.Analyzers/Analyzers/AutoPropertyAnalyzer.cs
--------------------------------------------------------------------------------
/src/Analyzers/Walterlv.CodeAnalysis.Analyzers/CodeFixes/AutoPropertyToAttachedPropertyCodeFixProvider.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Immutable;
3 | using System.Composition;
4 | using System.Linq;
5 | using System.Threading;
6 | using System.Threading.Tasks;
7 |
8 | using Microsoft.CodeAnalysis;
9 | using Microsoft.CodeAnalysis.CodeActions;
10 | using Microsoft.CodeAnalysis.CodeFixes;
11 | using Microsoft.CodeAnalysis.CSharp;
12 | using Microsoft.CodeAnalysis.CSharp.Syntax;
13 | using Microsoft.CodeAnalysis.Editing;
14 | using Microsoft.CodeAnalysis.Formatting;
15 | using Microsoft.CodeAnalysis.Simplification;
16 |
17 | using Walterlv.CodeAnalysis.Properties;
18 |
19 | namespace Walterlv.CodeAnalysis.CodeFixes
20 | {
21 | ///
22 | /// 自动属性转可通知属性。
23 | ///
24 | [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(AutoPropertyToAttachedPropertyCodeFixProvider)), Shared]
25 | public class AutoPropertyToAttachedPropertyCodeFixProvider : AutoPropertyToOtherCodeFixProvider
26 | {
27 | ///
28 | protected override string CodeActionTitle => Resources.AutoPropertyToAttachedPropertyFix;
29 |
30 | ///
31 | protected override void ChangePropertyCore(DocumentEditor editor, PropertyDeclarationSyntax propertySyntax)
32 | {
33 | var ownerType = (propertySyntax.Parent as ClassDeclarationSyntax)?.Identifier.ValueText;
34 | if (propertySyntax.AccessorList is null || ownerType is null)
35 | {
36 | return;
37 | }
38 |
39 | // 生成可通知属性的类型/名称/字段名称。
40 | var propertyType = propertySyntax.Type;
41 | propertyType = propertyType is NullableTypeSyntax nullableTypeSyntax ? nullableTypeSyntax.ElementType : propertyType;
42 | var propertyName = propertySyntax.Identifier.ValueText;
43 | var attachedPropertyName = $"{propertyName}Property";
44 |
45 | // 增加字段。
46 | editor.InsertBefore(propertySyntax, new SyntaxNode[]
47 | {
48 | // public static readonly DependencyProperty XxxProperty;
49 | SyntaxFactory.FieldDeclaration(
50 | new SyntaxList(),
51 | new SyntaxTokenList(
52 | SyntaxFactory.Token(SyntaxKind.PublicKeyword),
53 | SyntaxFactory.Token(SyntaxKind.StaticKeyword),
54 | SyntaxFactory.Token(SyntaxKind.ReadOnlyKeyword)),
55 | SyntaxFactory.VariableDeclaration(
56 | SyntaxFactory.ParseTypeName("System.Windows.DependencyProperty"),
57 | SyntaxFactory.SeparatedList(new[]
58 | {
59 | SyntaxFactory.VariableDeclarator(
60 | SyntaxFactory.Identifier(attachedPropertyName),
61 | null,
62 | SyntaxFactory.EqualsValueClause(
63 | SyntaxFactory.ParseExpression(@$"System.Windows.DependencyProperty.RegisterAttached(
64 | {"",4}""{propertyName}"", typeof({propertyType}), typeof({ownerType}),
65 | {"",4}new System.Windows.PropertyMetadata(default({propertyType})))")
66 | )
67 | )
68 | })
69 | ),
70 | SyntaxFactory.Token(SyntaxKind.SemicolonToken))
71 | .WithAdditionalAnnotations(new SyntaxAnnotation[] { Simplifier.Annotation, Formatter.Annotation })
72 | });
73 |
74 | editor.InsertBefore(
75 | propertySyntax,
76 | SyntaxFactory.ParseMemberDeclaration(
77 | $@"public static {propertySyntax.Type.ToFullString()}Get{propertyName}(System.Windows.DependencyObject element) => ({propertySyntax.Type.ToFullString()})element.GetValue({attachedPropertyName});")!
78 | .WithTrailingTrivia(SyntaxFactory.ParseTrailingTrivia(Environment.NewLine))
79 | .WithAdditionalAnnotations(new SyntaxAnnotation[] { Simplifier.Annotation, Formatter.Annotation })
80 | );
81 |
82 | editor.InsertBefore(
83 | propertySyntax,
84 | SyntaxFactory.ParseMemberDeclaration(
85 | $@"public static void Set{propertyName}(System.Windows.DependencyObject element, {propertySyntax.Type.ToFullString()} value) => element.SetValue({attachedPropertyName}, value);")!
86 | .WithLeadingTrivia(SyntaxFactory.ParseLeadingTrivia(Environment.NewLine))
87 | .WithAdditionalAnnotations(new SyntaxAnnotation[] { Simplifier.Annotation, Formatter.Annotation })
88 | );
89 |
90 | editor.RemoveNode(propertySyntax);
91 | }
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/src/Analyzers/Walterlv.CodeAnalysis.Analyzers/CodeFixes/AutoPropertyToDependencyPropertyCodeFixProvider.cs:
--------------------------------------------------------------------------------
1 | using System.Composition;
2 |
3 | using Microsoft.CodeAnalysis;
4 | using Microsoft.CodeAnalysis.CodeFixes;
5 | using Microsoft.CodeAnalysis.CSharp;
6 | using Microsoft.CodeAnalysis.CSharp.Syntax;
7 | using Microsoft.CodeAnalysis.Editing;
8 | using Microsoft.CodeAnalysis.Formatting;
9 | using Microsoft.CodeAnalysis.Simplification;
10 |
11 | using Walterlv.CodeAnalysis.Properties;
12 |
13 | namespace Walterlv.CodeAnalysis.CodeFixes
14 | {
15 | ///
16 | /// 自动属性转可通知属性。
17 | ///
18 | [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(AutoPropertyToDependencyPropertyCodeFixProvider)), Shared]
19 | public class AutoPropertyToDependencyPropertyCodeFixProvider : AutoPropertyToOtherCodeFixProvider
20 | {
21 | ///
22 | protected override string CodeActionTitle => Resources.AutoPropertyToDependencyPropertyFix;
23 |
24 | ///
25 | protected override void ChangePropertyCore(DocumentEditor editor, PropertyDeclarationSyntax propertySyntax)
26 | {
27 | var ownerType = (propertySyntax.Parent as ClassDeclarationSyntax)?.Identifier.ValueText;
28 | if (propertySyntax.AccessorList is null || ownerType is null)
29 | {
30 | return;
31 | }
32 |
33 | // 生成可通知属性的类型/名称/字段名称。
34 | var propertyType = propertySyntax.Type;
35 | propertyType = propertyType is NullableTypeSyntax nullableTypeSyntax ? nullableTypeSyntax.ElementType : propertyType;
36 | var propertyName = propertySyntax.Identifier.ValueText;
37 | var dependencyPropertyName = $"{propertyName}Property";
38 |
39 | // 增加字段。
40 | editor.InsertBefore(propertySyntax, new SyntaxNode[]
41 | {
42 | // public static readonly DependencyProperty XxxProperty;
43 | SyntaxFactory.FieldDeclaration(
44 | new SyntaxList(),
45 | new SyntaxTokenList(
46 | SyntaxFactory.Token(SyntaxKind.PublicKeyword),
47 | SyntaxFactory.Token(SyntaxKind.StaticKeyword),
48 | SyntaxFactory.Token(SyntaxKind.ReadOnlyKeyword)),
49 | SyntaxFactory.VariableDeclaration(
50 | SyntaxFactory.ParseTypeName("System.Windows.DependencyProperty"),
51 | SyntaxFactory.SeparatedList(new[]
52 | {
53 | SyntaxFactory.VariableDeclarator(
54 | SyntaxFactory.Identifier(dependencyPropertyName),
55 | null,
56 | SyntaxFactory.EqualsValueClause(
57 | SyntaxFactory.ParseExpression(@$"System.Windows.DependencyProperty.Register(
58 | {"",4}nameof({propertyName}), typeof({propertyType}), typeof({ownerType}),
59 | {"",4}new System.Windows.PropertyMetadata(default({propertyType})))")
60 | )
61 | )
62 | })
63 | ),
64 | SyntaxFactory.Token(SyntaxKind.SemicolonToken))
65 | .WithAdditionalAnnotations(new SyntaxAnnotation[] { Simplifier.Annotation, Formatter.Annotation })
66 | });
67 |
68 | // 替换 get/set。
69 | editor.ReplaceNode(
70 | propertySyntax,
71 | SyntaxFactory.ParseMemberDeclaration(
72 | $@"{propertySyntax.AttributeLists.ToFullString()}{propertySyntax.Modifiers.ToFullString()}{propertySyntax.Type.ToFullString()}{propertySyntax.Identifier.ToFullString()}
73 | {{
74 | get => ({propertyType})GetValue({dependencyPropertyName});
75 | set => SetValue({dependencyPropertyName}, value);
76 | }}")!
77 | .WithAdditionalAnnotations(new SyntaxAnnotation[] { Simplifier.Annotation, Formatter.Annotation })
78 | );
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/src/Analyzers/Walterlv.CodeAnalysis.Analyzers/CodeFixes/AutoPropertyToNotificationPropertyCodeFixProvider.cs:
--------------------------------------------------------------------------------
1 |
2 |
3 | using System.Composition;
4 | using System.Globalization;
5 |
6 | using Microsoft.CodeAnalysis;
7 | using Microsoft.CodeAnalysis.CodeFixes;
8 | using Microsoft.CodeAnalysis.CSharp;
9 | using Microsoft.CodeAnalysis.CSharp.Syntax;
10 | using Microsoft.CodeAnalysis.Editing;
11 | using Microsoft.CodeAnalysis.Formatting;
12 | using Microsoft.CodeAnalysis.Simplification;
13 |
14 | using Walterlv.CodeAnalysis.Properties;
15 |
16 | namespace Walterlv.CodeAnalysis.CodeFixes
17 | {
18 | ///
19 | /// 自动属性转可通知属性。
20 | ///
21 | [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(AutoPropertyToNotificationPropertyCodeFixProvider)), Shared]
22 | public class AutoPropertyToNotificationPropertyCodeFixProvider : AutoPropertyToOtherCodeFixProvider
23 | {
24 | ///
25 | protected override string CodeActionTitle => Resources.AutoPropertyToNotificationPropertyFix;
26 |
27 | ///
28 | protected override void ChangePropertyCore(DocumentEditor editor, PropertyDeclarationSyntax propertySyntax)
29 | {
30 | if (propertySyntax.AccessorList is null)
31 | {
32 | return;
33 | }
34 |
35 | // 生成可通知属性的类型/名称/字段名称。
36 | var propertyType = propertySyntax.Type;
37 | var propertyName = propertySyntax.Identifier.ValueText;
38 | var fieldName = $"_{char.ToLower(propertyName[0], CultureInfo.InvariantCulture)}{propertyName.Substring(1)}";
39 |
40 | // 增加字段。
41 | editor.InsertBefore(propertySyntax, new SyntaxNode[]
42 | {
43 | // private Type _field;
44 | SyntaxFactory.FieldDeclaration(
45 | new SyntaxList(),
46 | new SyntaxTokenList(SyntaxFactory.Token(SyntaxKind.PrivateKeyword)),
47 | SyntaxFactory.VariableDeclaration(
48 | propertyType,
49 | SyntaxFactory.SeparatedList(new[]
50 | {
51 | SyntaxFactory.VariableDeclarator(
52 | SyntaxFactory.Identifier(fieldName)
53 | )
54 | })
55 | ),
56 | SyntaxFactory.Token(SyntaxKind.SemicolonToken))
57 | });
58 |
59 | // 替换 get/set。
60 | editor.ReplaceNode(
61 | propertySyntax,
62 | SyntaxFactory.ParseMemberDeclaration(
63 | $@"{propertySyntax.AttributeLists.ToFullString()}{propertySyntax.Modifiers.ToFullString()}{propertySyntax.Type.ToFullString()}{propertySyntax.Identifier.ToFullString()}
64 | {{
65 | get => {fieldName};
66 | set => SetValue(ref {fieldName}, value);
67 | }}")!
68 | .WithAdditionalAnnotations(new SyntaxAnnotation[] { Simplifier.Annotation, Formatter.Annotation })
69 | );
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/Analyzers/Walterlv.CodeAnalysis.Analyzers/CodeFixes/AutoPropertyToOtherCodeFixProvider.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Immutable;
2 | using System.Linq;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 |
6 | using Microsoft.CodeAnalysis;
7 | using Microsoft.CodeAnalysis.CodeActions;
8 | using Microsoft.CodeAnalysis.CodeFixes;
9 | using Microsoft.CodeAnalysis.CSharp.Syntax;
10 | using Microsoft.CodeAnalysis.Editing;
11 |
12 | namespace Walterlv.CodeAnalysis.CodeFixes
13 | {
14 | ///
15 | /// 自动属性转其他种类的属性。
16 | ///
17 | public abstract class AutoPropertyToOtherCodeFixProvider : CodeFixProvider
18 | {
19 | ///
20 | public sealed override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(DiagnosticIds.AutoProperty);
21 |
22 | ///
23 | public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer;
24 |
25 | ///
26 | /// 重写以指定转换描述。
27 | ///
28 | protected abstract string CodeActionTitle { get; }
29 |
30 | ///
31 | public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
32 | {
33 | var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
34 | if (root is null)
35 | {
36 | return;
37 | }
38 |
39 | var diagnostic = context.Diagnostics.First();
40 | var diagnosticSpan = diagnostic.Location.SourceSpan;
41 |
42 | var declaration = (PropertyDeclarationSyntax)root.FindNode(diagnostic.Location.SourceSpan);
43 |
44 | context.RegisterCodeFix(
45 | CodeAction.Create(
46 | title: CodeActionTitle,
47 | createChangedDocument: ct => ConvertToOther(context.Document, declaration, ct),
48 | equivalenceKey: GetType().Name),
49 | diagnostic);
50 | }
51 |
52 | private async Task ConvertToOther(
53 | Document document,
54 | PropertyDeclarationSyntax propertyDeclarationSyntax,
55 | CancellationToken cancellationToken)
56 | {
57 | // 获取文档根语法节点。
58 | var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
59 | if (root is null)
60 | {
61 | return document;
62 | }
63 |
64 | // 修改文档。
65 | var editor = await DocumentEditor.CreateAsync(document).ConfigureAwait(false);
66 | ChangePropertyCore(editor, propertyDeclarationSyntax);
67 | return editor.GetChangedDocument();
68 | }
69 |
70 | ///
71 | /// 重写以转换属性。
72 | ///
73 | protected abstract void ChangePropertyCore(DocumentEditor editor, PropertyDeclarationSyntax typeSyntax);
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/src/Analyzers/Walterlv.CodeAnalysis.Analyzers/DiagnosticIds.cs:
--------------------------------------------------------------------------------
1 | namespace Walterlv.CodeAnalysis
2 | {
3 | internal static class DiagnosticIds
4 | {
5 | // 纯代码生成:WCA001-WCA199
6 | public const string AutoProperty = "WCA001";
7 |
8 | // 代码诊断和生成:WCA201-WCA999
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/Analyzers/Walterlv.CodeAnalysis.Analyzers/DiagnosticUrls.cs:
--------------------------------------------------------------------------------
1 | namespace Walterlv.CodeAnalysis
2 | {
3 | internal static class DiagnosticUrls
4 | {
5 | public static string Get(string diagnosticId)
6 | => $"https://github.com/dotnet-campus/dotnetCampus.CommandLine/docs/analyzers/{diagnosticId}.md";
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/Analyzers/Walterlv.CodeAnalysis.Analyzers/Properties/LocalizableStrings.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.CodeAnalysis;
2 |
3 | namespace Walterlv.CodeAnalysis.Properties
4 | {
5 | internal static class LocalizableStrings
6 | {
7 | public static LocalizableString Get(string key) => new LocalizableResourceString(key, Resources.ResourceManager, typeof(Resources));
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/Analyzers/Walterlv.CodeAnalysis.Analyzers/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // 此代码由工具生成。
4 | // 运行时版本:4.0.30319.42000
5 | //
6 | // 对此文件的更改可能会导致不正确的行为,并且如果
7 | // 重新生成代码,这些更改将会丢失。
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace Walterlv.CodeAnalysis.Properties {
12 | using System;
13 |
14 |
15 | ///
16 | /// 一个强类型的资源类,用于查找本地化的字符串等。
17 | ///
18 | // 此类是由 StronglyTypedResourceBuilder
19 | // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
20 | // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
21 | // (以 /str 作为命令选项),或重新生成 VS 项目。
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// 返回此类使用的缓存的 ResourceManager 实例。
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Walterlv.CodeAnalysis.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// 重写当前线程的 CurrentUICulture 属性
51 | /// 重写当前线程的 CurrentUICulture 属性。
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 |
63 | ///
64 | /// 查找类似 The property '{0}' is an auto property. 的本地化字符串。
65 | ///
66 | internal static string AutoPropertyDescription {
67 | get {
68 | return ResourceManager.GetString("AutoPropertyDescription", resourceCulture);
69 | }
70 | }
71 |
72 | ///
73 | /// 查找类似 The property '{0}' is an auto property. 的本地化字符串。
74 | ///
75 | internal static string AutoPropertyMessage {
76 | get {
77 | return ResourceManager.GetString("AutoPropertyMessage", resourceCulture);
78 | }
79 | }
80 |
81 | ///
82 | /// 查找类似 Auto property 的本地化字符串。
83 | ///
84 | internal static string AutoPropertyTitle {
85 | get {
86 | return ResourceManager.GetString("AutoPropertyTitle", resourceCulture);
87 | }
88 | }
89 |
90 | ///
91 | /// 查找类似 Change to attached property 的本地化字符串。
92 | ///
93 | internal static string AutoPropertyToAttachedPropertyFix {
94 | get {
95 | return ResourceManager.GetString("AutoPropertyToAttachedPropertyFix", resourceCulture);
96 | }
97 | }
98 |
99 | ///
100 | /// 查找类似 Change to dependency property 的本地化字符串。
101 | ///
102 | internal static string AutoPropertyToDependencyPropertyFix {
103 | get {
104 | return ResourceManager.GetString("AutoPropertyToDependencyPropertyFix", resourceCulture);
105 | }
106 | }
107 |
108 | ///
109 | /// 查找类似 Change to notification property 的本地化字符串。
110 | ///
111 | internal static string AutoPropertyToNotificationPropertyFix {
112 | get {
113 | return ResourceManager.GetString("AutoPropertyToNotificationPropertyFix", resourceCulture);
114 | }
115 | }
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/src/Analyzers/Walterlv.CodeAnalysis.Analyzers/Walterlv.CodeAnalysis.Analyzers.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 | enable
6 | Walterlv.CodeAnalysis
7 | false
8 | true
9 | false
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/src/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | true
7 | $(MSBuildThisFileDirectory)Walterlv.Packages.snk
8 | true
9 | true
10 | true
11 | snupkg
12 | true
13 | True
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/Directory.Build.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 | $(UserProfile)\.nuget\packages\microsoft.netframework.referenceassemblies.net45\1.0.2\build
7 | $(UserProfile)\.nuget\packages\microsoft.netframework.referenceassemblies.net40\1.0.2\build
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/Frameworks/Walterlv.Windows.Framework/Walterlv.Windows.Framework (Package)/Walterlv.Windows.Framework (Package).csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.0;net45;net5.0-windows10.0.19041.0
5 | Walterlv.Windows.Framework
6 | Miscellaneous
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/src/Frameworks/Walterlv.Windows.Framework/Walterlv.Windows.Framework.WinUI/Walterlv.Windows.Framework.WinUI.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net5.0-windows10.0.19041.0
5 | 10.0.17763.0
6 | win10-x86;win10-x64;win10-arm64
7 | Walterlv.Windows.Framework
8 | false
9 | false
10 | true
11 | $(DefineConstants);WINUI
12 | Walterlv
13 | This is an MVVM framework without any document.
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/src/Frameworks/Walterlv.Windows.Framework/Walterlv.Windows.Framework.Wpf/ComponentModel/BindableObject.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Collections.ObjectModel;
4 | using System.ComponentModel;
5 | using System.Runtime.CompilerServices;
6 |
7 | namespace Walterlv.ComponentModel
8 | {
9 | ///
10 | /// 表示可绑定的对象,在此类型的派生类中按约定定义的属性支持绑定。
11 | ///
12 | public abstract class BindableObject : INotifyPropertyChanged
13 | {
14 | #region PropertyChanged
15 |
16 | ///
17 | /// 当此实例中的任何一个具有更改通知的属性值改变时发生。
18 | /// 派生类可以通过调用 或 来引发此事件。
19 | ///
20 | public event PropertyChangedEventHandler? PropertyChanged;
21 |
22 | ///
23 | /// 当具有更改通知的属性值改变时发生。
24 | ///
25 | /// 属性名称。不需要手动传入,会自动根据所在属性的方法名设置此参数值。
26 | protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
27 | {
28 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
29 | }
30 |
31 | ///
32 | /// 修改一个具有更改通知的属性值,并对外报告值的改变。
33 | ///
34 | /// 值的类型。
35 | /// 要修改的字段引用。
36 | /// 要修改的字段的新值。
37 | /// 属性名称。不需要手动传入,会自动根据所在属性的方法名设置此参数值。
38 | /// 如果值发生了更改,则返回 true;否则返回 false。
39 | protected bool SetValue(ref T field, T value, [CallerMemberName] string? propertyName = null)
40 | {
41 | if (!Equals(field, value))
42 | {
43 | field = value;
44 | OnPropertyChanged(propertyName);
45 | return true;
46 | }
47 |
48 | return false;
49 | }
50 |
51 | #endregion
52 |
53 | #region Collection Updated
54 |
55 | ///
56 | /// 更新集合中的所有项,以便在不修改绑定实例的情况下通知 UI 更新所有项。
57 | /// 注意:此方法暂未进行性能优化,目前是全集合更新。
58 | ///
59 | /// 集合的单项类型。
60 | /// 要修改的字段引用。
61 | /// 更新集合需要使用的新集合
62 | protected static void UpdateCollection(ObservableCollection source, ICollection items)
63 | {
64 | source = source ?? throw new ArgumentNullException(nameof(source));
65 | if (ReferenceEquals(source, items))
66 | {
67 | throw new ArgumentException("更新使用的集合不允许是原集合。", nameof(items));
68 | }
69 |
70 | source.Clear();
71 |
72 | if (items is null)
73 | {
74 | return;
75 | }
76 |
77 | foreach (var item in items)
78 | {
79 | source.Add(item);
80 | }
81 | }
82 |
83 | #endregion
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/Frameworks/Walterlv.Windows.Framework/Walterlv.Windows.Framework.Wpf/Walterlv.Windows.Framework.Wpf.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.0;net45
5 | Walterlv.Windows.Framework
6 | Walterlv.Windows.Framework
7 | false
8 | true
9 | $(DefineConstants);WPF
10 | Walterlv
11 | This is an MVVM framework without any document.
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/Frameworks/Walterlv.Windows.Framework/Walterlv.Windows.Framework.Wpf/Windows/Input/ActionCommand.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows.Input;
3 |
4 | namespace Walterlv.Windows.Input
5 | {
6 | ///
7 | /// 为普通的动作提供 的实现。
8 | ///
9 | public class ActionCommand : ICommand
10 | {
11 | ///
12 | /// 创建 的新实例,当 被执行时,将调用参数传入的动作。
13 | ///
14 | public ActionCommand(Action action)
15 | {
16 | _action = action ?? throw new ArgumentNullException(nameof(action));
17 | }
18 |
19 | ///
20 | /// 此 中用于执行的任务本身。
21 | ///
22 | private readonly Action _action;
23 |
24 | ///
25 | /// 执行任务。
26 | ///
27 | void ICommand.Execute(object parameter)
28 | {
29 | if (parameter != null)
30 | {
31 | throw new ArgumentException(
32 | $"不能向 ActionCommand 指定参数,因为这里指定的参数无法传递。如果希望传递参数,请使用 {nameof(ActionCommand)} 的泛型版本。",
33 | nameof(parameter));
34 | }
35 |
36 | Execute();
37 | }
38 |
39 | ///
40 | /// 执行任务。
41 | ///
42 | public void Execute() => _action.Invoke();
43 |
44 | ///
45 | /// 判断命令何时可用。
46 | ///
47 | bool ICommand.CanExecute(object parameter) => true;
48 |
49 | ///
50 | /// 当命令的可执行性改变时发生。
51 | ///
52 | public event EventHandler? CanExecuteChanged;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/Frameworks/Walterlv.Windows.Framework/Walterlv.Windows.Framework.Wpf/Windows/Input/ActionCommand`1.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows.Input;
3 |
4 | namespace Walterlv.Windows.Input
5 | {
6 | ///
7 | /// 表示一个必须提供参数才能执行的命令。
8 | ///
9 | public class ActionCommand : ICommand
10 | {
11 | ///
12 | /// 创建 的新实例,当 被执行时,将调用参数传入的动作。
13 | ///
14 | public ActionCommand(Action action)
15 | {
16 | _action = action ?? throw new ArgumentNullException(nameof(action));
17 | }
18 |
19 | ///
20 | /// 用于接受所提供的参数并执行的委托。
21 | ///
22 | private readonly Action _action;
23 |
24 | ///
25 | /// 使用指定的参数执行此命令。
26 | /// 框架中没有约定参数值是否允许为 null,这由参数定义时的泛型类型约定(C#8.0)或由命令的实现者约定。
27 | ///
28 | public void Execute(T t) => _action(t);
29 |
30 | void ICommand.Execute(object parameter) => Execute((T)parameter);
31 |
32 | bool ICommand.CanExecute(object parameter) => true;
33 |
34 | ///
35 | ///
36 | /// 当命令的可执行性改变时发生。
37 | ///
38 | public event EventHandler? CanExecuteChanged;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/Frameworks/Walterlv.Windows.Framework/Walterlv.Windows.Framework.Wpf/Windows/Navigating/INavigationView.cs:
--------------------------------------------------------------------------------
1 | namespace Walterlv.Windows.Navigating
2 | {
3 | public interface INavigationView
4 | {
5 | }
6 | }
--------------------------------------------------------------------------------
/src/Frameworks/Walterlv.Windows.Framework/Walterlv.Windows.Framework.Wpf/Windows/Navigating/INavigationViewModel.cs:
--------------------------------------------------------------------------------
1 | namespace Walterlv.Windows.Navigating
2 | {
3 | public interface INavigationViewModel
4 | {
5 | }
6 | }
--------------------------------------------------------------------------------
/src/Frameworks/Walterlv.Windows.Framework/Walterlv.Windows.Framework.Wpf/Windows/Navigating/NavigationItem.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics.Contracts;
3 | using Walterlv.ComponentModel;
4 |
5 | #if WINUI
6 | using UIElement = Microsoft.UI.Xaml.UIElement;
7 | #else
8 | using UIElement = System.Windows.UIElement;
9 | #endif
10 |
11 | namespace Walterlv.Windows.Navigating
12 | {
13 | ///
14 | /// 为 Master-Detail 布局型导航提供通用的 ViewModel。
15 | ///
16 | public class NavigationItem : BindableObject
17 | {
18 | private readonly Func _viewCreator;
19 | private readonly Func