forked from AvaloniaUI/Avalonia
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Started adding a guide for WPF devs.
- Loading branch information
Showing
1 changed file
with
142 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
# Perspex for WPF Developers | ||
|
||
Perspex is in general very similar to WPF, but you will find differences. Here | ||
are the most common: | ||
|
||
## Styling | ||
|
||
The most obvious difference from other XAML frameworks is that Perspex uses a | ||
[CSS-like styling system](../spec/styles.md). Styles aren't stored in a | ||
`Resources` collection as in WPF, they are stored in a separate `Styles` | ||
collection: | ||
|
||
<UserControl> | ||
<UserControl.Styles> | ||
<!-- Make TextBlocks with the h1 style class have a font size of 24 points --> | ||
<Style Selector="TextBlock.h1"> | ||
<Setter Property="FontSize" Value="24"/> | ||
</Style> | ||
</UserControl.Styles> | ||
<TextBlock Classes="h1">Header</TextBlock> | ||
<UserControl> | ||
|
||
## DataTemplates | ||
|
||
As styles aren't stored in `Resources`, neither are `DataTemplates` ([in fact | ||
there is no `Resources` collection](#Resources)). Instead, `DataTemplates` are | ||
placed in a `DataTemplates` collection on each control (and on `Application`): | ||
|
||
<UserControl xmlns:viewmodels="clr-namespace:MyApp.ViewModels;assembly=MyApp"> | ||
<UserControl.DataTemplates> | ||
<DataTemplate DataType="viewmodels:FooViewModel"> | ||
<Border Background="Red" CornerRadius="8"> | ||
<TextBox Text="{Binding Name}"/> | ||
</Border> | ||
</DataTemplate> | ||
</UserControl.Styles> | ||
<!-- Assuming that DataContext.Foo is an object of type | ||
MyApp.ViewModels.FooViewModel then a red border with a corner | ||
radius of 8 containing a TextBox will be displayed here --> | ||
<ContentControl Content="{Binding Foo}"/> | ||
<UserControl> | ||
|
||
## UIElement, FrameworkElement and Control | ||
|
||
WPF's `UIElement` and `FrameworkElement` are non-templated control base classes, | ||
which roughly equate to the Perspex `Control` class. WPF's `Control` class on | ||
the other hand is a templated control - Perspex's equivalent of this is | ||
`TemplatedControl`. | ||
|
||
So to recap: | ||
|
||
- `UIElement`: `Control` | ||
- `FrameworkElement`: `Control` | ||
- `Control`: `TemplatedControl` | ||
|
||
## DependencyProperty | ||
|
||
The Perspex equivalent of `DependencyProperty` is `StyledProperty`, however | ||
Perspex [has a richer property system than WPF](../spec/defining-properties.md), | ||
and includes `DirectProperty` for turning standard CLR properties into Perspex | ||
properties. The common base class of `StyledProperty` and `DirectProperty` | ||
is `PerspexProperty`. | ||
|
||
# Resources | ||
|
||
There is no `Resources` collection on controls in Perspex, however `Style`s | ||
do have a `Resources` collection for style-related resources. These can be | ||
referred to using the `{StyleResource}` markup extension both inside and outside | ||
styles. | ||
|
||
For non-style-related resources, we suggest defining them in code and referring | ||
to them in markup using the `{Static}` markup extension. There are [various | ||
reasons](http://www.codemag.com/article/1501091) for this, but briefly: | ||
|
||
- Resources have to be parsed | ||
- The tree has to be traversed to find them | ||
- XAML doesn't handle immutable objects | ||
- XAML syntax can be long-winded compared to C# | ||
|
||
## Grid | ||
|
||
Perspex has a `Grid` panel just like WPF, however a common use of `Grid` in WPF | ||
is to stack two controls on top of each other. For this purpose in Perspex you | ||
can just use a `Panel` which is more lightweight than `Grid`. | ||
|
||
We don't yet support `SharedSizeScope` in `Grid`. | ||
|
||
## Tunnelling Events | ||
|
||
Perspex has tunnelling events (unlike UWP!) but they're not exposed via | ||
separate `Preview` CLR event handlers. To subscribe to a tunnelling event you | ||
must call `AddHandler` with `RoutingStrategies.Tunnel`: | ||
|
||
``` | ||
target.AddHandler(InputElement.KeyDownEvent, OnPreviewKeyDown, RoutingStrategies.Tunnel); | ||
void OnPreviewKeyDown(object sender, KeyEventArgs e) | ||
{ | ||
// Handler code | ||
} | ||
``` | ||
|
||
## Class Handlers | ||
|
||
In WPF, class handlers for events can be added by calling | ||
[EventManager.RegisterClassHandler](https://msdn.microsoft.com/en-us/library/ms597875.aspx). | ||
An example of registering a class handler in WPF might be: | ||
|
||
static MyControl() | ||
{ | ||
EventManager.RegisterClassHandler(typeof(MyControl), MyEvent, HandleMyEvent)); | ||
} | ||
|
||
private static void HandleMyEvent(object sender, RoutedEventArgs e) | ||
{ | ||
} | ||
|
||
The equivalent of this in Perspex would be: | ||
|
||
static MyControl() | ||
{ | ||
MyEvent.AddClassHandler<MyControl>(x => x.HandleMyEvent); | ||
} | ||
|
||
private void HandleMyEvent(object sender, RoutedEventArgs e) | ||
{ | ||
} | ||
|
||
Notice that in WPF you have to add the class handler as a static method, whereas | ||
in Perspex the class handler is not static: the notification is automatically | ||
directed to the correct instance. | ||
|
||
## PropertyChangedCallback | ||
|
||
Listening to changes on DependencyProperties in WPF can be complex. When you | ||
register a `DependencyProperty` you can supply a static `PropertyChangedCallback` | ||
but if you want to listen to changes from elsewhere [things can get complicated | ||
and error-prone](http://stackoverflow.com/questions/23682232). | ||
|
||
In Perspex, 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](../spec/working-with-properties.md#Subscribing%20%to%20%a%20%Property%20%on%20%Any%20%Object). |