1 changed files with 142 additions and 0 deletions
@ -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). |
|||
Loading…
Reference in new issue