Add samples how code looks in WPF and Avalonia
This commit is contained in:
Родитель
4e7a61f462
Коммит
9c82843945
|
@ -51,3 +51,115 @@ Avalonia is in general very similar to WPF, but you will find differences. Here
|
||||||
{% content-ref url="rendertransforms-and-rendertransformorigin.md" %}
|
{% content-ref url="rendertransforms-and-rendertransformorigin.md" %}
|
||||||
[rendertransforms-and-rendertransformorigin.md](rendertransforms-and-rendertransformorigin.md)
|
[rendertransforms-and-rendertransformorigin.md](rendertransforms-and-rendertransformorigin.md)
|
||||||
{% endcontent-ref %}
|
{% endcontent-ref %}
|
||||||
|
|
||||||
|
# Dispatcher changes
|
||||||
|
|
||||||
|
If you use `Application.Current.Dispatcher`, you should use `Dispatcher.UIThread` instead which provide similar facilities.
|
||||||
|
|
||||||
|
**WPF**
|
||||||
|
```
|
||||||
|
Application.Current.Dispatcher.InvokeAsync(handler, DispatcherPriority.Background);
|
||||||
|
```
|
||||||
|
|
||||||
|
**Avalonia**
|
||||||
|
```
|
||||||
|
Dispatcher.UIThread.InvokeAsync(handler, DispatcherPriority.Background);
|
||||||
|
```
|
||||||
|
|
||||||
|
If you previously access dispatcher on the control itself, you should use global static instance `Dispatcher.UIThread` too.
|
||||||
|
|
||||||
|
**WPF**
|
||||||
|
```
|
||||||
|
this.Dispatcher.InvokeAsync(handler, DispatcherPriority.Background);
|
||||||
|
```
|
||||||
|
|
||||||
|
**Avalonia**
|
||||||
|
```
|
||||||
|
Dispatcher.UIThread.InvokeAsync(handler, DispatcherPriority.Background);
|
||||||
|
```
|
||||||
|
|
||||||
|
In more details, it's explained in the [Accessing the UI thread](../../guides/basics/accessing-the-ui-thread.md) article.
|
||||||
|
|
||||||
|
# Visibility of elements
|
||||||
|
|
||||||
|
WPF has uses `Visibility` property which can be `Collapsed`, `Hidden` or `Visible`. Avalonia uses simpler and more intuitive model `bool IsVisible`.
|
||||||
|
|
||||||
|
# Binding
|
||||||
|
|
||||||
|
**WPF**
|
||||||
|
```
|
||||||
|
<TextBox Name="MyTextbox" Text="{Binding ElementName=searchTextBox, Path=Text}"" />
|
||||||
|
```
|
||||||
|
|
||||||
|
**Avalonia**
|
||||||
|
```
|
||||||
|
<TextBox Name="MyTextbox" Text="{Binding #searchTextBox.Text}" />
|
||||||
|
```
|
||||||
|
|
||||||
|
# Handling attachment to visual tree
|
||||||
|
|
||||||
|
There no events like `Loaded`/`Unloaded` in Avalonia, but you can override `OnAttachedToVisualTree`/`OnDetachedFromVisualTree` on the control, to know when control attached to virtual tree, or detatched from it. Alternatively you can use `TemplateApplied` instead of `Loaded` event.
|
||||||
|
|
||||||
|
**WPF**
|
||||||
|
```
|
||||||
|
Unloaded += OnControl_Unloaded;
|
||||||
|
Loaded += OnControl_Loaded;
|
||||||
|
|
||||||
|
private void OnControl_Loaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
// Handle control loaded event.
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnControl_Unloaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
// Handle control unload event.
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Avalonia**
|
||||||
|
```
|
||||||
|
TemplateApplied += OnControl_Loaded;
|
||||||
|
private void BuildControl_Loaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
// or
|
||||||
|
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
|
||||||
|
{
|
||||||
|
// Handle control loaded event.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use this instead of Unloaded event.
|
||||||
|
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
|
||||||
|
{
|
||||||
|
// Handle control unload event.
|
||||||
|
}
|
||||||
|
```
|
||||||
|
That mean that you cannot subscribe to tree attachment/detachment events for other controls.
|
||||||
|
|
||||||
|
|
||||||
|
# Tooltips
|
||||||
|
|
||||||
|
Avalonia controls does not have `ToolTip` property like WPF. Instead you should use `ToolTip.Tip`
|
||||||
|
|
||||||
|
**WPF**
|
||||||
|
```csharp
|
||||||
|
<Button ToolTip="Save file as..." />
|
||||||
|
```
|
||||||
|
|
||||||
|
**Avalonia**
|
||||||
|
```csharp
|
||||||
|
<Button ToolTip.Tip="Save file as..." />
|
||||||
|
```
|
||||||
|
|
||||||
|
# TextRun decorations
|
||||||
|
|
||||||
|
**WPF**
|
||||||
|
```csharp
|
||||||
|
TextRunProperties.SetTextDecorations(TextDecorations.Underline);
|
||||||
|
```
|
||||||
|
|
||||||
|
**Avalonia**
|
||||||
|
```csharp
|
||||||
|
TextRunProperties.Underline = true;
|
||||||
|
```
|
|
@ -2,3 +2,29 @@
|
||||||
|
|
||||||
The Avalonia equivalent of `DependencyProperty` is `StyledProperty`, however Avalonia [has a richer property system than WPF](https://docs.avaloniaui.net/docs/authoring-controls/defining-properties), and includes `DirectProperty` for turning standard CLR properties into Avalonia properties. The common base class of `StyledProperty` and `DirectProperty` is `AvaloniaProperty`.
|
The Avalonia equivalent of `DependencyProperty` is `StyledProperty`, however Avalonia [has a richer property system than WPF](https://docs.avaloniaui.net/docs/authoring-controls/defining-properties), and includes `DirectProperty` for turning standard CLR properties into Avalonia properties. The common base class of `StyledProperty` and `DirectProperty` is `AvaloniaProperty`.
|
||||||
|
|
||||||
|
If your dependency property uses `FrameworkPropertyMetadataOptions.AffectsMeasure` now you should use `AffectsMeasure<TControl>(MyProperty)` to obtain desired effect.
|
||||||
|
|
||||||
|
**WPF**
|
||||||
|
```csharp
|
||||||
|
// SplitterPanel control
|
||||||
|
public static readonly DependencyProperty OrientationProperty =
|
||||||
|
DependencyProperty.Register(
|
||||||
|
"Orientation",
|
||||||
|
typeof(Orientation),
|
||||||
|
typeof(SplitterPanel),
|
||||||
|
new FrameworkPropertyMetadata(
|
||||||
|
Orientation.Horizontal,
|
||||||
|
FrameworkPropertyMetadataOptions.AffectsMeasure));
|
||||||
|
```
|
||||||
|
|
||||||
|
**Avalonia**
|
||||||
|
```csharp
|
||||||
|
// SplitterPanel control
|
||||||
|
public static readonly StyledProperty<Orientation> OrientationProperty =
|
||||||
|
AvaloniaProperty.Register<SplitterPanel, Orientation>(nameof(Orientation), Orientation.Horizontal);
|
||||||
|
|
||||||
|
static SplitterPanel()
|
||||||
|
{
|
||||||
|
AffectsMeasure<SplitterPanel>(OrientationProperty);
|
||||||
|
}
|
||||||
|
```
|
|
@ -1,4 +1,14 @@
|
||||||
# ItemsControl
|
# ItemsControl
|
||||||
|
|
||||||
In WPF, `ItemsControl` and derived classes such as `ListBox` have two separate items properties: `Items` and `ItemsSource`. Avalonia however just has a single one: `Items`.
|
In WPF, `ItemsControl` and derived classes such as `ListBox` have two separate items properties: `Items` and `ItemsSource`. Avalonia however just has a single one: `Items` which is same as WPF `ItemsSource` property.
|
||||||
|
|
||||||
|
## Before
|
||||||
|
```csharp
|
||||||
|
contextMenu.Items.Add(runItem);
|
||||||
|
```
|
||||||
|
|
||||||
|
## After
|
||||||
|
```csharp
|
||||||
|
var list = contextMenu.Items as IList;
|
||||||
|
list?.Add(runItem);
|
||||||
|
```
|
|
@ -4,3 +4,56 @@ Listening to changes on DependencyProperties in WPF can be complex. When you reg
|
||||||
|
|
||||||
In Avalonia, there is no `PropertyChangedCallback` at the time of registration, instead a class listener is [added to the control's static constructor in much the same way that event class listeners are added](https://docs.avaloniaui.net/docs/data-binding/binding-from-code#subscribing-to-a-property-on-any-object).
|
In Avalonia, there is no `PropertyChangedCallback` at the time of registration, instead a class listener is [added to the control's static constructor in much the same way that event class listeners are added](https://docs.avaloniaui.net/docs/data-binding/binding-from-code#subscribing-to-a-property-on-any-object).
|
||||||
|
|
||||||
|
As side effect of this change, you may need to dispatch events yourself.
|
||||||
|
**WPF**
|
||||||
|
```csharp
|
||||||
|
treeView.SelectedItemChanged += TreeView_SelectedItemChanged;
|
||||||
|
|
||||||
|
// ...
|
||||||
|
|
||||||
|
private void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
|
||||||
|
{
|
||||||
|
var item = treeView.SelectedItem;
|
||||||
|
// work with selected item.
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Avalonia**
|
||||||
|
```csharp
|
||||||
|
treeView.PropertyChanged += TreeView_SelectedItemChanged;
|
||||||
|
|
||||||
|
// ...
|
||||||
|
|
||||||
|
private void TreeView_SelectedItemChanged(object sender, AvaloniaPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.Property != TreeView.SelectedItemProperty) return;
|
||||||
|
|
||||||
|
var item = treeView.SelectedItem;
|
||||||
|
// work with selected item.
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Even plain text box should be handled in same way.
|
||||||
|
**WPF**
|
||||||
|
```csharp
|
||||||
|
searchTextBox.TextChanged += new TextChangedEventHandler(searchTextBox_TextChanged);
|
||||||
|
|
||||||
|
private void searchTextBox_TextChanged(object sender, TextChangedEventArgs e)
|
||||||
|
{
|
||||||
|
// handle text change
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Avalonia**
|
||||||
|
```csharp
|
||||||
|
searchTextBox.PropertyChanged += searchTextBox_TextChanged;
|
||||||
|
|
||||||
|
// ...
|
||||||
|
|
||||||
|
private void searchTextBox_TextChanged(object sender, AvaloniaPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.Property != TextBox.TextProperty) return;
|
||||||
|
|
||||||
|
// handle text change
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
Загрузка…
Ссылка в новой задаче