Skip to content

Commit b95dac6

Browse files
committed
grrr
1 parent 2200166 commit b95dac6

File tree

11 files changed

+299
-60
lines changed

11 files changed

+299
-60
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Duck Typing in CSharp
2+
3+
Currently only `GetEnumerator` and `Deconstruct` supports duck typing.
4+
`Dispose` is just not available since you the compiler won't be able to know which one to pick if there's duplication.
5+
6+
```cs
7+
using System.Collections;
8+
9+
using var foo = new Foo(); // [!code error]
10+
foreach (var _ in new Foo()) ;
11+
var (a, b) = new Foo();
12+
13+
class Foo;
14+
15+
static class FooExtension
16+
{
17+
public static void Dispose(this Foo self) => Console.WriteLine("Disposing Foo");
18+
public static IEnumerator GetEnumerator(this Foo _)
19+
{
20+
for (int i = 0; i < 100; i++)
21+
yield return i;
22+
}
23+
public static void Deconstruct(this Foo self, out object? a, out object? b) => a = b = null;
24+
}
25+
```
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Adding New Style
2+
3+
## With dotnet cli
4+
5+
```sh
6+
dotnet new avalonia.styles -o Styles -n NewStyle
7+
```
8+
9+
## Default Template
10+
11+
Style template ships with a portion for previewer where you can add testing controls to see whether those styles works properly.
12+
13+
```xml
14+
<Styles xmlns="https://github.com/avaloniaui"
15+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
16+
<Design.PreviewWith> <!-- [!code highlight] -->
17+
<Border Padding="20"> <!-- [!code highlight] -->
18+
<!-- Add Controls for Previewer Here --> <!-- [!code highlight] -->
19+
</Border> <!-- [!code highlight] -->
20+
</Design.PreviewWith> <!-- [!code highlight] -->
21+
22+
<!-- Add Styles Here -->
23+
</Styles>
24+
```
25+
26+
## Define a Style
27+
28+
A style starts with a `Selector` which is the rule of target matching, for figuring out which control should have those contained styling.
29+
Contained styling is some key-value pair on properties.
30+
31+
> [!NOTE]
32+
> See [selector syntax]()
33+
34+
```xml
35+
<Styles xmlns="https://github.com/avaloniaui"
36+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
37+
<Design.PreviewWith> <!-- [!code highlight] -->
38+
<Border Padding="20"> <!-- [!code highlight] -->
39+
<!-- Add Controls for Previewer Here --> <!-- [!code highlight] -->
40+
</Border> <!-- [!code highlight] -->
41+
</Design.PreviewWith> <!-- [!code highlight] -->
42+
43+
<!-- Add Styles Here -->
44+
<Style Selector="TextBlock.h1"> <!-- [!code ++] -->
45+
<Setter Property="FontWeight" Value="Bold" /> <!-- [!code ++] -->
46+
<Setter Property="FontSize" Value="15" /> <!-- [!code ++] -->
47+
<Setter Property="Margin" Value="5" /> <!-- [!code ++] -->
48+
</Style> <!-- [!code ++] -->
49+
50+
</Styles>
51+
```
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
## Importing Styles
2+
3+
```xml
4+
<UserControl xmlns="https://github.com/avaloniaui"
5+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
6+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
7+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
8+
xmlns:control="using:AvaloniaApplication"
9+
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
10+
x:Class="AvaloniaApplication.MyUserControl">
11+
12+
<UserControl.Styles> <!-- [!code highlight] -->
13+
<StyleInclude Source="MyStyles.axaml"></StyleInclude> <!-- [!code highlight] -->
14+
</UserControl.Styles> <!-- [!code highlight] -->
15+
16+
<TextBlock Text="Hello from template" TextAlignment="Center" Width="200" Height="20"/>
17+
18+
</UserControl>
19+
```

β€Ždocs/document/Avalonia/docs/2. Styling/Selector Syntax.mdβ€Ž

Lines changed: 0 additions & 7 deletions
This file was deleted.

β€Ždocs/document/Avalonia/docs/2. Styling/Style Isolation.mdβ€Ž

Lines changed: 0 additions & 45 deletions
This file was deleted.
Lines changed: 135 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,137 @@
11
# Trigger a Command
22

3-
## RelayCommand
3+
`CommunityToolkit.Mvvm` uses `RelayCommand` to generate a field and property to represents the command for certain method.
4+
5+
## Code Emission
6+
7+
```cs
8+
[RelayCommand]
9+
private void RemoveItem(ToDoItemViewModel item)
10+
{
11+
ToDoItems.Remove(item);
12+
}
13+
```
14+
15+
Generated part as following:
16+
17+
- A field of type `RelayCommand`(not the `RelayCommandAttribute`)
18+
- A property for the generated field typed as `IRelayCommand`.
19+
20+
```cs
21+
/// <summary>The backing field for <see cref="RemoveItemCommand"/>.</summary>
22+
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.RelayCommandGenerator", "8.3.0.0")]
23+
private global::CommunityToolkit.Mvvm.Input.RelayCommand<global::ToDoList.ViewModels.ToDoItemViewModel>? removeItemCommand; // [!code highlight]
24+
/// <summary>Gets an <see cref="global::CommunityToolkit.Mvvm.Input.IRelayCommand{T}"/> instance wrapping <see cref="RemoveItem"/>.</summary>
25+
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.RelayCommandGenerator", "8.3.0.0")]
26+
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
27+
public global::CommunityToolkit.Mvvm.Input.IRelayCommand<global::ToDoList.ViewModels.ToDoItemViewModel> RemoveItemCommand => removeItemCommand ??= new global::CommunityToolkit.Mvvm.Input.RelayCommand<global::ToDoList.ViewModels.ToDoItemViewModel>(new global::System.Action<global::ToDoList.ViewModels.ToDoItemViewModel>(RemoveItem)); // [!code highlight]
28+
```
29+
30+
## Behind the `RelayCommand`
31+
32+
To understand how `RelayCommand` works, we should go back to the story of `ICommand` first.
33+
34+
`ICommand` is a builtin interface in .NET, has three parts to describe the command pattern:
35+
- `Execute`: A real action for the command.
36+
- `CanExecute`: Telling whether the command can be executed now.
37+
- `CanExecuteChanged`: Informing when `CanExecute` evaluation changed.
38+
39+
```cs
40+
public interface ICommand
41+
{
42+
/// <summary>Occurs when changes occur that affect whether or not the command should execute.</summary>
43+
event EventHandler? CanExecuteChanged;
44+
45+
/// <summary>Defines the method that determines whether the command can execute in its current state.</summary>
46+
/// <param name="parameter">Data used by the command. If the command does not require data to be passed, this object can be set to <see langword="null" />.</param>
47+
/// <returns>
48+
/// <see langword="true" /> if this command can be executed; otherwise, <see langword="false" />.</returns>
49+
bool CanExecute(object? parameter);
50+
51+
/// <summary>Defines the method to be called when the command is invoked.</summary>
52+
/// <param name="parameter">Data used by the command. If the command does not require data to be passed, this object can be set to <see langword="null" />.</param>
53+
void Execute(object? parameter);
54+
}
55+
```
56+
57+
`IRelayCommand` in `CommunityToolkit` simply extends the `ICommand` with a new notify method.
58+
We do need a real implementation of how we inform on `CanExecuteChanged`, this is generally missing in .NET builtin event-driven interfaces.
59+
60+
```cs
61+
public interface IRelayCommand : ICommand
62+
{
63+
/// <summary>
64+
/// Notifies that the <see cref="ICommand.CanExecute"/> property has changed. // [!code highlight]
65+
/// </summary>
66+
void NotifyCanExecuteChanged();
67+
}
68+
```
69+
70+
> [!NOTE]
71+
> `IRelayCommand` and `RelayCommand` have generic versions and async versions.
72+
73+
The type of generated field is `RelayCommand` which implements the `IRelayCommand`, this is essentially a base wrapper for the logic behind.
74+
75+
```cs
76+
public sealed partial class RelayCommand : IRelayCommand
77+
{
78+
/// <summary>
79+
/// The <see cref="Action"/> to invoke when <see cref="Execute"/> is used.
80+
/// </summary>
81+
private readonly Action execute;
82+
83+
/// <summary>
84+
/// The optional action to invoke when <see cref="CanExecute"/> is used.
85+
/// </summary>
86+
private readonly Func<bool>? canExecute;
87+
88+
/// <inheritdoc/>
89+
public event EventHandler? CanExecuteChanged;
90+
91+
/// <summary>
92+
/// Initializes a new instance of the <see cref="RelayCommand"/> class that can always execute.
93+
/// </summary>
94+
/// <param name="execute">The execution logic.</param>
95+
/// <exception cref="System.ArgumentNullException">Thrown if <paramref name="execute"/> is <see langword="null"/>.</exception>
96+
public RelayCommand(Action execute)
97+
{
98+
ArgumentNullException.ThrowIfNull(execute);
99+
100+
this.execute = execute;
101+
}
102+
103+
/// <summary>
104+
/// Initializes a new instance of the <see cref="RelayCommand"/> class.
105+
/// </summary>
106+
/// <param name="execute">The execution logic.</param>
107+
/// <param name="canExecute">The execution status logic.</param>
108+
/// <exception cref="System.ArgumentNullException">Thrown if <paramref name="execute"/> or <paramref name="canExecute"/> are <see langword="null"/>.</exception>
109+
public RelayCommand(Action execute, Func<bool> canExecute)
110+
{
111+
ArgumentNullException.ThrowIfNull(execute);
112+
ArgumentNullException.ThrowIfNull(canExecute);
113+
114+
this.execute = execute;
115+
this.canExecute = canExecute;
116+
}
117+
118+
/// <inheritdoc/>
119+
public void NotifyCanExecuteChanged()
120+
{
121+
CanExecuteChanged?.Invoke(this, EventArgs.Empty);
122+
}
123+
124+
/// <inheritdoc/>
125+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
126+
public bool CanExecute(object? parameter)
127+
{
128+
return this.canExecute?.Invoke() != false;
129+
}
130+
131+
/// <inheritdoc/>
132+
public void Execute(object? parameter)
133+
{
134+
this.execute();
135+
}
136+
}
137+
```

β€Ždocs/document/Csharp Design Patterns/docs/Behavioural/Interpreter.mdβ€Ž

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,4 +217,7 @@ var tokens = Lex("(1 + 3) - (5 + 2)");
217217
var operation = Parse<int>(CollectionsMarshal.AsSpan(tokens));
218218
Console.WriteLine(operation.Value); // -3
219219
```
220-
## ANTLR
220+
221+
> [!TIP]
222+
> Manually writing parsers are very tedious, use certain tools to parse your language instead.
223+
> ANTLR, bison, yacc for example.
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Function
2+
3+
## Parameter
4+
5+
There's no positional parameters, it's a table-like definition, can be specified with any order.
6+
Parameters are wrapped inside a function block with `param(...)`
7+
8+
```ps1
9+
function Foo {
10+
param (
11+
[string]$foo
12+
)
13+
}
14+
```
15+
16+
### Default Parameter
17+
18+
```ps1
19+
function Foo {
20+
param (
21+
[string]$foo = "foo"
22+
)
23+
}
24+
```
25+
26+
### Flags
27+
28+
Defining flags that represents a toggle needs a special type called `switch`.
29+
`switch` has the same nature of `bool`, but `bool` parameter requires explicit assignment when the function being called.
30+
While `switch` will remain `$false` when unspecified.
31+
32+
```ps1
33+
function Foo {
34+
param (
35+
[switch]$foo
36+
[bool]$bar
37+
)
38+
}
39+
40+
# this is why we should use `switch` instead.
41+
Foo -foo -bar $true # [!code highlight]
42+
```
43+
44+
### Required Parameter
45+
46+
All parameters are optional by default. Use `[Parameter(Mandatory=$true)]` to mark it as required.
47+
48+
```ps1
49+
param (
50+
[Parameter(Mandatory=$true)]
51+
[string]$RequiredName
52+
)
53+
```
54+
55+
## Lifetime
56+
57+
- Function should be define before it was called.

β€Ždocs/services/DocumentService.tsβ€Ž

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,16 @@ export const documentMap = {
1919
// VBA: { icon: 'πŸ’©', description: 'VBA for excel' },
2020
// Vue3: { icon: '⚑', description: '' },
2121
'Unsafe CSharp': { icon: '😎', description: 'Entering the danger zone...' },
22-
'NeoVim ColorScheme Development': {
23-
icon: '🎨',
24-
description: 'Make your own nvim color scheme using lua.',
25-
},
22+
// 'NeoVim ColorScheme Development': {
23+
// icon: '🎨',
24+
// description: 'Make your own nvim color scheme using lua.',
25+
// },
2626
Bash: { icon: '🐒', description: 'Shebang!' },
2727
'Regular Expression': { icon: '🐫', description: 'Memory lossss for every 6 months' },
2828
Nix: { icon: '❄', description: 'Reproduce freedom' },
2929
'Entity Framework Core': { icon: 'πŸ—Ώ', description: '' },
3030
'HTML & CSS': { icon: '😬', description: '' },
31+
Powershell: { icon: '🐚', description: '...' },
3132
} as const satisfies DocumentInfo;
3233

3334
export type DocumentName = keyof typeof documentMap;

β€Ždocs/services/SidebarService.tsβ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { execSync } from 'node:child_process';
2-
import path from 'node:path';
2+
import path = require('node:path');
33
import type { DefaultTheme } from 'vitepress';
44
import { type DirectoryInfo, type FileInfo, Path, documentRoot } from '../shared/FileSystem';
55
import { type DocumentName, documentMap, documentService } from './DocumentService';

0 commit comments

Comments
Β (0)