Skip to content

Commit 9271f2c

Browse files
committed
docs(ListState): Add Tutorials about Binding ListState to ListView and Updating specific Items
1 parent 46a4adc commit 9271f2c

14 files changed

+747
-2
lines changed

README.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ The [Mvux Gallery](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/tree/master
4949

5050
#### Featured Controls
5151

52-
- **FeedView** combined with GridView and ListView
52+
- **FeedView** combined with **GridView** and **ListView**
5353
- **DataTemplate** centralized resource definitions
5454
- **Card**, **Grid**, **NavigationView**
5555
- **ItemOverlayTemplate** (replicated from WinUI 3 Gallery)
@@ -99,8 +99,15 @@ A complete tutorial application demonstrating navigation patterns with MVUX and
9999

100100
A basic application demonstrating selection and display of member names in a `ListView` bound to a `ListState<string>` in the Model using MVUX.
101101

102+
**Tutorial Documentation available:**
103+
104+
- **MVUX State Management Tutorials** - Learn how to use `ListState` and `ListFeed` alongside with `ListView` and `Button.Command`-Binding (🇩🇪 [German](https://devtkss.github.io/DevTKSS.Uno.SampleApps/articles/de/Mvux-StateManagement/Overview-de.html) | 🇬🇧 [English](https://devtkss.github.io/DevTKSS.Uno.SampleApps/articles/en/Mvux-StateManagement/HowTo-Binding-ListState-and-ListFeed-de.md))
105+
106+
**Video Tutorials available:**
107+
102108
- **[Video Tutorial - How To: Binden von ListState und ImmutableList zu FeedView & ListView im UI | Uno Community Tutorial](https://youtu.be/wOsSlv1YFic)** - Step-by-step guide (🇩🇪 German)
103-
- **[Source Code](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/tree/master/src/DevTKSS.Uno.SimpleMemberSelectionApp/)**
109+
- **[Video Tutorial Series](https://youtube.com/playlist?list=PLEL6kb4Bivm_g81iKBl-f0eYPNr5h2dFX)** - Complete walkthrough (🇩🇪 German with English subtitles)
110+
- **[Source Code](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/tree/master/src/DevTKSS.Uno.XamlNavigationApp-1/)** - Browse the implementation
104111

105112
---
106113

29.5 KB
Loading
64.8 KB
Loading
870 KB
Loading
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
---
2+
uid: DevTKSS.Uno.MvuxStateManagement.ListState.Selection.de
3+
---
4+
# Anleitung: Binding von ListState mit Selection
5+
6+
## Überblick
7+
8+
In diesem Beispiel zeigen wir dir, wie du ein `ListState` aus deinem Model an eine `ListView` bindest und wie du die Auswahl eines Elements verfolgst. Wir erstellen eine einfache Mitgliederlisten-Anzeige, bei der du:
9+
10+
- Eine Liste von Mitgliedern in einer `ListView` anzeigen kannst
11+
- Ein Mitglied aus der `ListView` auswählen kannst
12+
- Das ausgewählte Mitglied oben auf der Seite angezeigt bekommst
13+
14+
Dieses Beispiel zeigt die Grundlagen des `.Selection(...)`-Operators, der sowohl mit `IListState<T>` als auch mit `IListFeed<T>` funktioniert.
15+
16+
## Voraussetzungen
17+
18+
Bevor du mit diesem Tutorial beginnst, stelle sicher, dass du:
19+
20+
- [Anleitung: Erstellen einer Uno Platform App](xref:DevTKSS.Uno.Setup.HowTo-CreateNewUnoApp.de) abgeschlossen hast
21+
- [Anleitung: Hinzufügen neuer Pages](xref:DevTKSS.Uno.Setup.HowTo-AddingNewPages.de) abgeschlossen hast
22+
- [Anleitung: Hinzufügen neuer MVUX Model-Klassen](xref:DevTKSS.Uno.Setup.HowTo-AddingNew-VM-Class-Record.de) abgeschlossen hast
23+
- Grundlegendes Verständnis von Dependency Injection aus [Anleitung: Verwendung von DI im Constructor](xref:DevTKSS.Uno.Setup.Using-DI-in-ctor.de) hast
24+
25+
## Visuelle Referenz
26+
27+
![Mitgliederlisten UI mit Selection](../../.attachments/Binding-ListState-FeedView.png)
28+
29+
## Das Model Setup
30+
31+
Zunächst definieren wir die States, die für die Anzeige und Auswahl benötigt werden.
32+
33+
### Initialisierung von ListState
34+
35+
Es gibt zwei gängige Möglichkeiten, den `ListState<T>` zu initialisieren:
36+
37+
#### [Verwendung von `ListState.Async(...)`](#tab/Async)
38+
39+
Mit der `ListState<string>.Async(...)`-Methode kannst du eine asynchrone Methode bereitstellen, die einmal aufgerufen wird, um die anfängliche Liste der Mitglieder zu erhalten. Dies ist nützlich, wenn du Daten asynchron aus einer API oder Datenbank laden musst.
40+
41+
```csharp
42+
private readonly IImmutableList<string> _listMembers = ImmutableList.Create(
43+
[
44+
"Hans",
45+
"Lisa",
46+
"Anke",
47+
"Tom"
48+
]);
49+
50+
private async ValueTask<IImmutableList<string>> GetMembersAsync(CancellationToken ct)
51+
=> _listMembers;
52+
53+
public IListState<string> Members => ListState<string>.Async(this, GetMembersAsync)
54+
.Selection(SelectedMember);
55+
56+
public IState<string> SelectedMember => State<string>.Value(this, () => string.Empty);
57+
```
58+
59+
Die Schlüsselelemente in diesem Code:
60+
61+
- `_listMembers` - Eine statische unveränderliche Liste, die unsere Mitgliedernamen enthält
62+
- `GetMembersAsync(...)` - Asynchrone Methode, die die Liste zurückgibt (obwohl es sich um statische Daten handelt)
63+
- `Members` - `IListState<string>` initialisiert über `Async(...)` mit `.Selection(...)`-Operator
64+
- `SelectedMember` - `IState<string>`, das das aktuell ausgewählte Mitglied verfolgt
65+
66+
**Hinweis:** Obwohl dieser Ansatz funktioniert, erfordert er erheblichen Boilerplate-Code (Feld + asynchrone Methode + ListState-Property), selbst für statische Daten, die eigentlich kein asynchrones Laden benötigen.
67+
68+
#### [Verwendung von `ListState.Value(...)`](#tab/Value)
69+
70+
Mit der `ListState<string>.Value(...)`-Methode kannst du eine statische Liste von Mitgliedern direkt in einer einzigen Zeile bereitstellen. Dieser Ansatz reduziert den Boilerplate drastisch und eignet sich perfekt für Demonstrationszwecke oder beim Umgang mit statischen Daten.
71+
72+
```csharp
73+
public IListState<string> Members => ListState<string>.Value(this,
74+
() => ImmutableList.Create(
75+
[
76+
"Hans",
77+
"Lisa",
78+
"Anke",
79+
"Tom"
80+
])
81+
).Selection(SelectedMember);
82+
83+
public IState<string> SelectedMember => State<string>.Value(this, () => string.Empty);
84+
```
85+
86+
**Vorteile gegenüber dem Async-Ansatz:**
87+
88+
- **90% weniger Code** - Kein separates Feld oder asynchrone Methode erforderlich
89+
- **Mehrzeilige Definition** - Klarer, lesbarer Property-Ausdruck mit ordnungsgemäßer Formatierung
90+
- **Sofortige Klarheit** - Du kannst die Daten direkt dort sehen, wo sie definiert sind
91+
- **Gleiche Funktionalität** - Erhält trotzdem den `.Selection(...)`-Operator und alle ListState-Features
92+
- **Ideal für statische Daten** - Kein unnötiger asynchroner Overhead für bereits verfügbare Daten
93+
94+
> [!TIP]
95+
> **Wann Value vs Async verwenden:**
96+
>
97+
> - **Verwende `.Value(...)`**, wenn deine Daten statisch sind, aus Konstanten stammen oder synchron berechnet werden
98+
> - **Verwende `.Async(...)`**, wenn du tatsächlich Daten aus einer API, Datenbank abrufen oder asynchrone Operationen durchführen musst
99+
100+
***
101+
102+
## Die View (XAML)
103+
104+
Nachdem wir nun unser Model mit den erforderlichen States eingerichtet haben, erstellen wir die UI. Unsere UI besteht aus einem `TextBlock`, der das ausgewählte Mitglied anzeigt, und einer `ListView` zur Anzeige aller Mitglieder:
105+
106+
```xaml
107+
<StackPanel Spacing="16">
108+
<!-- Display selected member -->
109+
<TextBlock
110+
Text="{Binding Path=SelectedMember, Mode=OneWay}"
111+
FontSize="24"
112+
FontWeight="Bold"/>
113+
114+
<!-- List of all members -->
115+
<ListView
116+
ItemsSource="{Binding Path=Members}"
117+
SelectionMode="Single"
118+
Height="300"/>
119+
</StackPanel>
120+
```
121+
122+
> [!WARNING]
123+
> Wenn du das `ListView`-Control verwendest, stelle sicher, dass du die `ItemClickCommand`-Eigenschaft der `ListView` **nicht** gleichzeitig mit dem `.Selection(...)`-Operator des `ListState` setzt, da dies das Auswahlverhalten beeinträchtigt und den State, den du zur Widerspiegelung der aktuellen Auswahl verwendest, nicht wie erwartet aktualisiert. Du musst dich für eine der beiden Optionen entscheiden.
124+
125+
Beachte die wichtigsten Bindings:
126+
127+
- `ItemsSource="{Binding Path=Members}"` - bindet an unser `IListState<string>`
128+
- `Text="{Binding Path=SelectedMember, Mode=OneWay}"` - zeigt das ausgewählte Mitglied an
129+
130+
## Zusammenfassung
131+
132+
Dieses Beispiel demonstriert:
133+
134+
1. Binding von `IListState<T>` an eine `ListView` mit `.Selection(...)`-Operator (funktioniert auch mit `IListFeed<T>`)
135+
2. Verwendung eines separaten `IState<string>` zur Verfolgung der Auswahl
136+
3. Anzeige des ausgewählten Elements in der UI
137+
4. Zwei Initialisierungsmethoden: `.Async(...)` für echte asynchrone Daten vs `.Value(...)` für statische Daten
138+
139+
- [Link zum Source Code](../../../../src/DevTKSS.Uno.XamlNavigationApp-1/Presentation/DashboardModel.cs)
140+
141+
Im nächsten Tutorial lernst du, wie du die ausgewählten Elemente bearbeiten und aktualisieren kannst.
142+
143+
- [Nächstes Tutorial: Aktualisierung von ListState Items](xref:DevTKSS.Uno.MvuxStateManagement.ListState.UpdateItems.de)]
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
---
2+
uid: DevTKSS.Uno.Mvux-StateManagement.Overview.de
3+
---
4+
# Übersicht: Mvux State Management
5+
6+
## Einführung
7+
8+
In dieser Tutorial-Serie lernst du, wie du `ListState` und `ListFeed` in deinen Uno Platform MVUX-Apps verwendest. Diese Komponenten ermöglichen dir die reaktive Verwaltung von Listen-Daten mit automatischer UI-Aktualisierung.
9+
10+
## Was ist der Unterschied zwischen ListFeed und ListState?
11+
12+
- **`IListFeed<T>`** - Schreibgeschützte read-only Daten-Sammlungen (z.B. Server-Antworten)
13+
- Unterstützt `RequestRefreshAsync` oder `RefreshAsync` und den `.Selection(...)` Operator
14+
- Kein Support für `ForEach`-Callbacks oder direkte Item-Updates via bspw. `UpdateAllAsync(...)`
15+
16+
- **`IListState<T>`** - read-write Daten-Sammlungen
17+
- Ermöglicht direkte Aktualisierung und Key-matching Updates von Elementen mit `UpdateAllAsync(...)` oder `UpdateItemAsync(...)`
18+
- Unterstützt `ForEach`-Callbacks für die Verarbeitung von Elementen
19+
- Unterstützt `AddAsync`/`RemoveAsync`-Operationen
20+
- Ebenfalls kompatibel mit dem `.Selection(...)` Operator
21+
22+
## Tutorial-Serie
23+
24+
Diese Serie besteht aus zwei aufeinander aufbauenden Tutorials:
25+
26+
### 1. [Binding von ListState mit Selection](xref:DevTKSS.Uno.MvuxStateManagement.ListState-Selection.de)
27+
28+
In diesem ersten Tutorial lernst du die Grundlagen:
29+
30+
- Wie du ein `ListState` an eine `ListView` bindest
31+
- Wie du den `.Selection(...)` Operator verwendest
32+
- Wie du das ausgewählte Element in der UI anzeigst
33+
- Unterschiede zwischen `.Async(...)` und `.Value(...)` Initialisierung
34+
35+
### 2. [Aktualisierung von ListState Items](xref:DevTKSS.Uno.MvuxStateManagement.Update-ListStateItems.de)
36+
37+
Im zweiten Tutorial erweitern wir die Funktionalität:
38+
39+
- Wie du Elemente in einem `ListState` bearbeitest
40+
- Verwendung von `UpdateAllAsync(...)` mit Filterkriterien
41+
- Einsatz von `[FeedParameter]` für saubereres State-Handling
42+
- Warum `IListState<T>` für Aktualisierungen erforderlich ist
43+
44+
## Voraussetzungen
45+
46+
Bevor du mit diesen Tutorials beginnst, stelle sicher, dass du:
47+
48+
- [Anleitung: Erstellen einer Uno Platform App](xref:DevTKSS.Uno.Setup.HowTo-CreateNewUnoApp.de) abgeschlossen hast
49+
- [Anleitung: Hinzufügen neuer Pages](xref:DevTKSS.Uno.Setup.HowTo-AddingNewPages.de) abgeschlossen hast
50+
- [Anleitung: Hinzufügen neuer MVUX Model-Klassen](xref:DevTKSS.Uno.Setup.HowTo-AddingNew-VM-Class-Record.de) abgeschlossen hast
51+
- Grundlegendes Verständnis von Dependency Injection aus [Anleitung: Verwendung von DI im Constructor](xref:DevTKSS.Uno.Setup.Using-DI-in-ctor.de) hast
52+
53+
## Los geht's
54+
55+
Beginne mit dem ersten Tutorial: [Binding von ListState mit Selection](xref:DevTKSS.Uno.MvuxStateManagement.ListState-Selection.de)
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
---
2+
uid: DevTKSS.Uno.MvuxStateManagement.ListState.UpdateItems.de
3+
---
4+
# Anleitung: Aktualisierung von ListState Items
5+
6+
## Überblick
7+
8+
In diesem Tutorial erweitern wir das vorherige Beispiel und fügen die Möglichkeit hinzu, Elemente in einem `ListState` zu bearbeiten. Du wirst lernen:
9+
10+
- Wie du einen zusätzlichen State für Benutzereingaben erstellst
11+
- Wie du `UpdateAllAsync(...)` verwendest, um Elemente zu aktualisieren
12+
- Wie du `[FeedParameter]` für saubereres State-Handling nutzt
13+
- Warum wir `IListState<T>` anstelle von `IListFeed<T>` für Aktualisierungen benötigen
14+
15+
Dieses Szenario zeigt, warum wir `ListState` anstelle von `ListFeed` benötigen: Während `ListFeed` nur `RequestRefresh` oder `Refresh` Aktionen unterstützt (die einen neuen API-/Service-Aufruf erfordern), ermöglicht `ListState` die direkte Aktualisierung von Elementen in der Liste mithilfe von Filterkriterien.
16+
17+
## Voraussetzungen
18+
19+
Bevor du mit diesem Tutorial beginnst, stelle sicher, dass du:
20+
21+
- [Anleitung: Binding von ListState mit Selection](xref:DevTKSS.Uno.MvuxStateManagement.ListState-Selection.de) abgeschlossen hast
22+
- Das vorherige Tutorial mit der grundlegenden ListState-Bindung verstanden hast
23+
24+
## Visuelle Referenz
25+
26+
![Mitgliederlisten-Editor mit Update-Funktion](../../.attachments/MvuxListApp-ListState-UpdateAllAsync.gif)
27+
28+
## Erweiterung des Models
29+
30+
Wir erweitern unser bestehendes Model um einen zusätzlichen State für die Bearbeitung und eine Methode zum Aktualisieren:
31+
32+
### Zusätzlicher State für die Bearbeitung
33+
34+
Wir benötigen einen State, um den geänderten Mitgliedernamen zu halten, den du eingibst:
35+
36+
```csharp
37+
public IState<string> ModifiedMemberName => State<string>.Empty(this);
38+
```
39+
40+
Dieser State ist bidirektional an die `TextBox` gebunden und erfasst deine Eingabe.
41+
42+
### Vollständiges Model
43+
44+
So sieht dein vollständiges Model aus:
45+
46+
```csharp
47+
public partial record MainModel
48+
{
49+
public IListState<string> Members => ListState<string>.Value(this,
50+
() => ImmutableList.Create(
51+
[
52+
"Hans",
53+
"Lisa",
54+
"Anke",
55+
"Tom"
56+
])
57+
).Selection(SelectedMember);
58+
59+
public IState<string> SelectedMember => State<string>.Value(this, () => string.Empty);
60+
61+
public IState<string> ModifiedMemberName => State<string>.Empty(this);
62+
}
63+
```
64+
65+
## Erweiterte View (XAML)
66+
67+
Jetzt fügen wir die Bearbeitungselemente zur UI hinzu:
68+
69+
[!code-xaml[](../../../../src/DevTKSS.Uno.MvuxListApp/Presentation/MainPage.xaml#MembersView?highlight=18,23,27,30)]
70+
71+
Die neuen Bindings:
72+
73+
- `Text="{Binding Path=ModifiedMemberName, Mode=TwoWay}"` - bidirektionales Binding für die Bearbeitung
74+
- `Command="{Binding Path=RenameMemberAsync}"` - löst die Umbenennungsoperation aus
75+
76+
## Implementierung des Rename-Befehls
77+
78+
> [!NOTE]
79+
> Wir verwenden einen schaltflächengesteuerten Befehl anstelle eines `.ForEach(...)`-Callbacks, um dir die explizite Kontrolle darüber zu geben, wann die Umbenennung erfolgt. Dies verhindert unbeabsichtigte Änderungen, wenn du:
80+
>
81+
> - Das falsche Mitglied ausgewählt hast
82+
> - Noch die korrekte Schreibweise nachschlägst
83+
> - Deine Meinung über die Umbenennung änderst
84+
85+
Hier ist die Befehlsimplementierung:
86+
87+
```csharp
88+
public async ValueTask RenameMemberAsync(
89+
[FeedParameter(nameof(ModifiedMemberName))] string? modName,
90+
[FeedParameter(nameof(SelectedMember))] string? replaceMember,
91+
CancellationToken ct)
92+
{
93+
if (string.IsNullOrWhiteSpace(modName))
94+
return;
95+
96+
await Members.UpdateAllAsync(
97+
match: item => item == replaceMember,
98+
updater: _ => modName,
99+
ct: ct
100+
);
101+
102+
await Members.TrySelectAsync(modName, ct);
103+
}
104+
```
105+
106+
Wichtige Punkte:
107+
108+
- **`UpdateAllAsync(...)`** - Aktualisiert Elemente im `ListState`, die den Filterkriterien entsprechen
109+
- **`match: item => item == replaceMember`** - Findet das aktuell ausgewählte Mitglied
110+
- **`updater: _ => modName`** - Ersetzt es durch den neuen Namen
111+
- **`TrySelectAsync(...)`** - Wählt das Mitglied erneut anhand seines neuen Namens aus
112+
113+
## Verwendung des FeedParameter-Attributs
114+
115+
Beachte die `[FeedParameter]`-Attribute auf den Methodenparametern. Diese leistungsstarke Funktion wartet automatisch auf State-Werte und bindet sie an deine Methodenparameter, wodurch manuelle `await`-Aufrufe eliminiert werden:
116+
117+
```csharp
118+
[FeedParameter(nameof(ModifiedMemberName))] string? modName,
119+
[FeedParameter(nameof(SelectedMember))] string? replaceMember
120+
```
121+
122+
> [!TIP]
123+
> **Vorteile:**
124+
>
125+
> - Kein manuelles `await` der States innerhalb der Methode erforderlich
126+
> - Parameter können andere Namen als die ursprünglichen States haben (verbessert die Lesbarkeit)
127+
> - Sauberere, fokussiertere Methodenimplementierung
128+
129+
**Alternative:** Verwende `[ImplicitFeedParameter]` auf Klassenebene, um alle Parameter automatisch zu binden, indem Namen exakt mit deinen States übereinstimmen:
130+
131+
```csharp
132+
[ImplicitFeedParameter]
133+
public partial record MainModel
134+
{
135+
...
136+
137+
public async ValueTask RenameMemberAsync(
138+
string? ModifiedMemberName,
139+
string? SelectedMember,
140+
CancellationToken ct)
141+
{ ... }
142+
}
143+
```
144+
145+
Mit `[ImplicitFeedParameter]` auf der Klasse werden alle Methodenparameter automatisch gebunden, indem ihre Namen exakt mit deinen State-Property-Namen übereinstimmen. Das bedeutet:
146+
147+
- Der Parameter `ModifiedMemberName` bindet automatisch an den `ModifiedMemberName`-State
148+
- Der Parameter `SelectedMember` bindet automatisch an den `SelectedMember`-State
149+
- Keine individuellen `[FeedParameter]`-Attribute für jeden Parameter erforderlich
150+
- Parameternamen müssen exakt mit State-Namen übereinstimmen (Groß-/Kleinschreibung beachten)
151+
152+
## Zusammenfassung
153+
154+
Dieses Beispiel demonstriert:
155+
156+
1. Verwendung von bidirektionalem Binding für Benutzereingaben über `IState<string>`
157+
2. Aktualisierung von Listenelementen mit `UpdateAllAsync(...)` - nur verfügbar bei `IListState<T>` (nicht `IListFeed<T>`)
158+
3. Befehlsbasierte Aktualisierungen für explizite Benutzerkontrolle
159+
4. Nutzung von `[FeedParameter]` für saubereres asynchrones State-Handling
160+
161+
Dieses Muster gewährleistet Datenkonsistenz und gibt dir die volle Kontrolle darüber, wann Änderungen in den Daten erfolgen und wann auch nicht.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# yaml-language-server: $schema=https://raw.githubusercontent.com/dotnet/docfx/main/schemas/toc.schema.json
2+
- name: Übersicht: ListState und ListFeed
3+
uid: DevTKSS.Uno.Mvux-StateManagement.Overview.de
4+
href: HowTo-Binding-ListState-and-ListFeed-de.md
5+
- name: Binding von ListState mit Selection
6+
uid: DevTKSS.Uno.MvuxStateManagement.ListState.Selection.de
7+
href: HowTo-Binding-ListState-Selection-de.md
8+
- name: Aktualisierung von ListState Items
9+
uid: DevTKSS.Uno.MvuxStateManagement.ListState.UpdateItems.de
10+
href: HowTo-Update-ListState-Items-de.md

0 commit comments

Comments
 (0)