Skip to content

Commit 0e0bb9d

Browse files
authored
Merge pull request w-ahmad#391 from w-ahmad/w-ahmad-docs-complete-feature-documentation
docs: add complete how-to documentation for all TableView features
2 parents 21afb4f + 6c05b70 commit 0e0bb9d

39 files changed

Lines changed: 3250 additions & 67 deletions

.github/workflows/ci-build.yml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,6 @@ on:
88
- 'samples/**'
99
pull_request:
1010
branches: main
11-
paths-ignore:
12-
- 'docs/**'
13-
- 'samples/**'
1411

1512
jobs:
1613
build:

.github/workflows/ci-docs.yml

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ on:
55
branches: main
66
paths-ignore:
77
- 'samples/**'
8+
pull_request:
9+
branches: main
10+
paths-ignore:
11+
- 'samples/**'
812

913
jobs:
1014
build:
@@ -30,11 +34,22 @@ jobs:
3034
- name: Build documentation
3135
run: docfx docs/docfx.json
3236

33-
- uses: actions/upload-pages-artifact@v3
37+
- name: Upload site artifact (PR preview)
38+
if: github.event_name == 'pull_request'
39+
uses: actions/upload-artifact@v4
40+
with:
41+
name: docs-site
42+
path: artifacts/_site
43+
retention-days: 14
44+
45+
- name: Upload pages artifact (deploy)
46+
if: github.event_name == 'push'
47+
uses: actions/upload-pages-artifact@v3
3448
with:
3549
path: artifacts/_site
3650

3751
publish-docs:
52+
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
3853
needs: [build]
3954
environment:
4055
name: github-pages

docs/docs/aot-compatibility.md

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
# Native AOT compatibility
2+
3+
`TableView` relies on runtime bindings and dynamic value resolution for features like sorting, filtering, editing, clipboard, and export. These mechanisms are not fully compatible with IL trimming and Native AOT by default. This page explains what you need to do to make your app work correctly under `<PublishAot>true</PublishAot>`.
4+
5+
> **See also:** [Native AOT deployment overview (.NET)](https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/) · [C#/WinRT overview](https://learn.microsoft.com/en-us/windows/apps/develop/platform/csharp-winrt/)
6+
7+
## When this applies
8+
9+
You need to follow this guidance if **any** of the following are true for your project:
10+
11+
- `<PublishAot>true</PublishAot>` is set in your `.csproj`
12+
- `<PublishTrimmed>true</PublishTrimmed>` is set in your `.csproj`
13+
- You see AOT/trimming warnings related to `WinRT` or binding at compile time
14+
15+
## The rule
16+
17+
> Any model class whose **properties are accessed via traditional `{Binding}` expressions** must be marked with `[WinRT.GeneratedBindableCustomProperty]` and declared as `partial`.
18+
19+
Traditional binding (`{Binding PropertyName}`) resolves property values at runtime using the WinRT binding infrastructure. Under Native AOT, that infrastructure requires the `[WinRT.GeneratedBindableCustomProperty]` attribute to generate the necessary binding metadata at compile time. This attribute is part of [C#/WinRT](https://github.com/microsoft/CsWinRT).
20+
21+
## What needs the attribute
22+
23+
### Bound columns (attribute required)
24+
25+
Columns that use a `Binding` property — all built-in bound column types — resolve values at runtime through the WinRT binding system:
26+
27+
```xml
28+
<tv:TableViewTextColumn Header="Name" Binding="{Binding Name}" />
29+
<tv:TableViewNumberColumn Header="Price" Binding="{Binding Price}" />
30+
<tv:TableViewCheckBoxColumn Header="Active" Binding="{Binding IsActive}" />
31+
<tv:TableViewDateColumn Header="Due" Binding="{Binding DueDate}" />
32+
<tv:TableViewTimeColumn Header="Time" Binding="{Binding ActiveAt}" />
33+
<tv:TableViewComboBoxColumn Header="Role" Binding="{Binding Role}" />
34+
<tv:TableViewHyperlinkColumn Header="Url" Binding="{Binding Url}" />
35+
```
36+
37+
Any model class whose properties are accessed by these columns **must** have the attribute.
38+
39+
### Template columns with `{Binding}` (attribute required)
40+
41+
If your `CellTemplate` or `EditingTemplate` uses `{Binding}` to access model properties, the attribute is still required:
42+
43+
```xml
44+
<tv:TableViewTemplateColumn Header="Status">
45+
<tv:TableViewTemplateColumn.CellTemplate>
46+
<DataTemplate>
47+
<!-- {Binding} requires the attribute on the model -->
48+
<TextBlock Text="{Binding StatusLabel}" />
49+
</DataTemplate>
50+
</tv:TableViewTemplateColumn.CellTemplate>
51+
</tv:TableViewTemplateColumn>
52+
```
53+
54+
### Template columns with `{x:Bind}` (attribute NOT required)
55+
56+
When a `TableViewTemplateColumn` uses `{x:Bind}` exclusively in its templates, the binding is compiled at build time and does **not** require the attribute on the model:
57+
58+
```xml
59+
<tv:TableViewTemplateColumn Header="Status">
60+
<tv:TableViewTemplateColumn.CellTemplate>
61+
<DataTemplate x:DataType="local:Product">
62+
<!-- x:Bind generates compile-time code — no attribute needed -->
63+
<TextBlock Text="{x:Bind StatusLabel}" />
64+
</DataTemplate>
65+
</tv:TableViewTemplateColumn.CellTemplate>
66+
</tv:TableViewTemplateColumn>
67+
```
68+
69+
## How to apply the attribute
70+
71+
Add `[WinRT.GeneratedBindableCustomProperty]` to your model class and mark it as `partial`:
72+
73+
```csharp
74+
using WinRT;
75+
76+
[GeneratedBindableCustomProperty]
77+
public partial class Product
78+
{
79+
public string? Name { get; set; }
80+
public double Price { get; set; }
81+
public bool InStock { get; set; }
82+
}
83+
```
84+
85+
> **Important:** The class **must** be `partial`. Without `partial`, the source generator cannot emit the required binding implementation and the build will fail.
86+
87+
## Using CommunityToolkit.Mvvm
88+
89+
If your models use [`ObservableObject`](https://learn.microsoft.com/en-us/dotnet/communitytoolkit/mvvm/observableobject) from [CommunityToolkit.Mvvm](https://learn.microsoft.com/en-us/dotnet/communitytoolkit/mvvm/), combine both attributes. Use `partial` properties with [`[ObservableProperty]`](https://learn.microsoft.com/en-us/dotnet/communitytoolkit/mvvm/generators/observableproperty) as normal:
90+
91+
```csharp
92+
using CommunityToolkit.Mvvm.ComponentModel;
93+
using WinRT;
94+
95+
[GeneratedBindableCustomProperty]
96+
public partial class Product : ObservableObject
97+
{
98+
[ObservableProperty]
99+
public partial string? Name { get; set; }
100+
101+
[ObservableProperty]
102+
public partial double Price { get; set; }
103+
104+
[ObservableProperty]
105+
public partial bool InStock { get; set; }
106+
}
107+
```
108+
109+
## Nested models
110+
111+
If a column binds to a nested property (e.g. `Binding="{Binding Address.City}"`), the **nested type** must also have the attribute:
112+
113+
```csharp
114+
[GeneratedBindableCustomProperty]
115+
public partial class Order
116+
{
117+
[ObservableProperty]
118+
public partial string? OrderNumber { get; set; }
119+
120+
[ObservableProperty]
121+
public partial Address? ShippingAddress { get; set; }
122+
}
123+
124+
[GeneratedBindableCustomProperty] // Required because columns bind into Address properties
125+
public partial class Address
126+
{
127+
[ObservableProperty]
128+
public partial string? City { get; set; }
129+
130+
[ObservableProperty]
131+
public partial string? Country { get; set; }
132+
}
133+
```
134+
135+
## Project configuration
136+
137+
Enable AOT and set the CsWinRT warning level to catch any remaining issues at build time:
138+
139+
```xml
140+
<PropertyGroup>
141+
<PublishAot>true</PublishAot>
142+
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
143+
<CsWinRTAotWarningLevel>2</CsWinRTAotWarningLevel>
144+
</PropertyGroup>
145+
146+
<!-- Trim only for Release builds -->
147+
<PropertyGroup>
148+
<PublishTrimmed Condition="'$(Configuration)' != 'Debug'">true</PublishTrimmed>
149+
</PropertyGroup>
150+
```
151+
152+
`CsWinRTAotWarningLevel=2` upgrades [CsWinRT](https://github.com/microsoft/CsWinRT) AOT hints to errors so missing attributes are caught during the build rather than at runtime.
153+
154+
## Notes and limitations
155+
156+
- Only WinUI 3 (Windows) targets support Native AOT. Uno Platform targets have their own AOT characteristics — consult the [Uno Platform documentation](https://platform.uno/docs/articles/uno-development/aot-compilation.html) for those targets.
157+
- `AutoGenerateColumns="True"` uses reflection to discover properties. This works with the attribute in place, but for maximum AOT compatibility prefer explicit columns (`AutoGenerateColumns="False"`).
158+
- `SortMemberPath` uses reflection-based property access when set. Ensure the model has the attribute when using `SortMemberPath`.
159+
160+
## Related articles
161+
162+
- [Binding data](binding-data.md)
163+
- [Defining columns](defining-columns.md)
164+
- [Column types](column-types.md)
165+
- [Performance guidance](performance.md)
166+
- [.NET Native AOT deployment overview](https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/)
167+
- [C#/WinRT overview](https://learn.microsoft.com/en-us/windows/apps/develop/platform/csharp-winrt/)
168+
- [CommunityToolkit.Mvvm](https://learn.microsoft.com/en-us/dotnet/communitytoolkit/mvvm/)
169+
- [CsWinRT on GitHub](https://github.com/microsoft/CsWinRT)

docs/docs/binding-data.md

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
# Binding data
2+
3+
`TableView` accepts any `IEnumerable` as its items source. For the best experience, use `ObservableCollection<T>` so that item additions and removals are reflected automatically, and implement `INotifyPropertyChanged` on your model so that cell values update when the underlying data changes.
4+
5+
## When to use it
6+
7+
Use data binding when you have a collection of objects whose properties map to table columns. This is the standard pattern for all TableView usage.
8+
9+
## Basic example
10+
11+
```xml
12+
<tv:TableView ItemsSource="{x:Bind Products}" />
13+
```
14+
15+
```csharp
16+
public sealed partial class MainWindow : Window
17+
{
18+
public ObservableCollection<Product> Products { get; } = new();
19+
20+
public MainWindow()
21+
{
22+
InitializeComponent();
23+
Products.Add(new Product { Name = "Widget", Price = 9.99, InStock = true });
24+
Products.Add(new Product { Name = "Gadget", Price = 24.50, InStock = false });
25+
}
26+
}
27+
```
28+
29+
## Model example
30+
31+
For editable cells, implement `INotifyPropertyChanged` so that changes committed in the editing control propagate back to the UI:
32+
33+
```csharp
34+
public class Product : INotifyPropertyChanged
35+
{
36+
private string? _name;
37+
private double _price;
38+
private bool _inStock;
39+
40+
public string? Name
41+
{
42+
get => _name;
43+
set { _name = value; OnPropertyChanged(nameof(Name)); }
44+
}
45+
46+
public double Price
47+
{
48+
get => _price;
49+
set { _price = value; OnPropertyChanged(nameof(Price)); }
50+
}
51+
52+
public bool InStock
53+
{
54+
get => _inStock;
55+
set { _inStock = value; OnPropertyChanged(nameof(InStock)); }
56+
}
57+
58+
public event PropertyChangedEventHandler? PropertyChanged;
59+
60+
private void OnPropertyChanged(string name) =>
61+
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
62+
}
63+
```
64+
65+
## Common options
66+
67+
| Property | Type | Default | Description |
68+
|---|---|---|---|
69+
| [`ItemsSource`](xref:WinUI.TableView.TableView.ItemsSource) | `object` | `null` | The data collection to display. |
70+
| [`AutoGenerateColumns`](xref:WinUI.TableView.TableView.AutoGenerateColumns) | `bool` | `true` | When `true`, columns are generated automatically from the public properties of the item type. |
71+
72+
## Using CollectionView
73+
74+
`TableView` wraps your source in an internal `AdvancedCollectionView`. You can access it through `TableView.CollectionView` to apply programmatic sort and filter descriptions.
75+
76+
```csharp
77+
// Sort by price descending
78+
tableView.SortDescriptions.Add(new SortDescription("Price", SortDirection.Descending));
79+
```
80+
81+
## Live shaping
82+
83+
The internal collection view supports live shaping. When you update a property on an item, sorting and filtering re-evaluate automatically:
84+
85+
```csharp
86+
tableView.AllowLiveShaping = true;
87+
```
88+
89+
Live shaping has a performance cost on large collections. Disable it if you do not need items to re-sort or re-filter when individual properties change.
90+
91+
## Notes and limitations
92+
93+
- Setting [`ItemsSource`](xref:WinUI.TableView.TableView.ItemsSource) to `null` clears the table.
94+
- If you replace the entire collection (by assigning a new list to [`ItemsSource`](xref:WinUI.TableView.TableView.ItemsSource)) any applied sort or filter descriptions are preserved on the internal view and applied to the new source.
95+
- The internal [`CollectionView`](xref:WinUI.TableView.TableView.CollectionView) is read-only; do not cast and mutate it directly. Use `TableView.SortDescriptions` and `TableView.FilterDescriptions` instead.
96+
97+
## Related articles
98+
99+
- [AutoGenerateColumns and defining columns](defining-columns.md)
100+
- [Sorting](sorting.md)
101+
- [Filtering](filtering.md)

0 commit comments

Comments
 (0)