Skip to content

Instantly share code, notes, and snippets.

@markjulmar
Created April 28, 2017 22:14
Show Gist options
  • Save markjulmar/18dff90ca8f7cd7373b7d650281681b3 to your computer and use it in GitHub Desktop.
Save markjulmar/18dff90ca8f7cd7373b7d650281681b3 to your computer and use it in GitHub Desktop.
Comparing WPF and Forms

WPF vs. Xamarin.Forms

Xamarin.Forms takes a lot of design guidance from the XAML-based frameworks that came before it, particularly WPF. However, in other ways it deviates significantly which can be a sticky point for people attempting to migrate over. This document attempts to identify some of those issues and provide guidance where possible to bridge WPF knowledge to Xamarin.Forms.

App Lifecycle

The application lifecycle between WPF and Xamarin.Forms is similar. Both start in external (platform) code and launch the UI through a method call. The difference is that Xamarin.Forms always starts in a platform-specific assembly which then initializes and creates the UI for the app.

WPF

Main method > App > MainWindow

Note that the Main method is, by default, auto generated and not visible in the code.

Xamarin.Forms

iOS: Main method > AppDelegate > App > ContentPage
Android: MainActivity > App > ContentPage
UWP: Main method > App(UWP) > MainPage(UWP) > App > ContentPage

Application class

Both WPF and Xamarin.Forms have an Application class which is created as a singleton. In most cases, apps will derive from this class to provide a custom application, although this is not strictly required in WPF. Both expose an Application.Current property to locate the created singleton.

Global properties + persistence

Both WPF and Xamarin.Forms have a Application.Properties dictionary available where you can store global app-level objects that are accessible anywhere in the application. The key difference is that Xamarin.Forms will persist any primitive types stored in the collection when the app is suspended, and reload them when it is relaunched. WPF does not automatically support that behavior - instead, most developers relied on isolated storage, or utilized the built-in Settings support.

Defining pages and the Visual Tree

WPF uses the Window as the root element for any top-level visual element. This defines an HWND in the Windows world to display information. You can create and display as many windows simultaneously as you like in WPF.

In Xamarin.Forms, the top-level visual is always defined by the platform - for example on iOS, it's a UIWindow. Xamarin.Forms renders it's content into these native platform representations using a Page class. Each Page in Xamarin.Forms represents a unique "page" in the application, where only one is visible at a time.

Both WPFs Window and Xamarin.Forms Page include a Title property to influence the displayed title, and both have an Icon property to display a specific icon for the page (Note that the title and icon are not always visible in Forms). In addition, you can change common visual properties on both such as the background color or image.

It is technically possible to render to two separate platform views (e.g. define two UIWindow objects and have the second one render to an external display or AirPlay), it requires platform-specific code to do so and is not a directly supported feature of Xamarin.Forms itself.

Views

The visual hierachy for both frameworks is similar. WPF is a bit deeper due to it's support for WYSIWYG documents.

WPF

DependencyObject - base class for all bindable things
   Visual - rendering mechanics
      UIElement - common events + interactions
         FrameworkElement - adds layout
            Shape - 2D graphics
            Control - interactive controls

Xamarin.Forms

BindableObject - base class for all bindable things
   Element - basic parent/child support + resources + effects
      VisualElement - adds visual rendering properties (color, fonts, transforms, etc.)
         View - layout + gesture support

View Lifcycle

Xamarin.Forms is primarily oriented around mobile scenarios. As such, applications are activated, suspended, and reactivated as the user interacts with them. This is similar to clicking away from the Window in a WPF application and there are a set of methods and corresponding events you can override or hook into to monitor this behavior.

Purpose WPF Method Xamarin.Forms Method
Initial activation ctor + Window.OnLoaded ctor + Page.OnStart
Shown Window.IsVisibleChanged Page.Appearing
Hidden Window.IsVisibleChanged Page.Disapearing
Suspend/Lost focus Window.OnDeactivated Page.OnSleep
Activated/Got focus Window.OnActivated Page.OnResume
Closed Window.OnClosing + Window.OnClosed n/a

Both support hiding/showing child controls as well, in WPF it's a tri-state property IsVisible (visible, hidden, and collapsed). In Xamarin.Forms, it's just visible or hidden through the IsVisible property.

Layout

Page layout occurs in the same 2-pass (Measure/Arrange) that happens in WPF. You can hook into the page layout by overriding the following methods in the Xamarin.Forms Page class:

Method Purpose
OnChildMeasureInvalidated Preferred size of a child has changed.
OnSizeAllocated Page has been assigned a width/height.
LayoutChanged event Layout/size of the Page has changed

There is no global layout event which is called today, nor is there a global CompositionTarget.Rendering event like found in WPF.

Common layout properties

WPF and Xamarin.Forms both support Margin to control spacing around an element, and Padding to control spacing inside an element. In addition, most of the Xamarin.Forms layout views have properties to control spacing (e.g. row or column).

In addition, most elements have properties to influence how they are positioned in the parent container:

WPF Xamarin.Forms Purpose
HorizontalAlignment HorizontalOptions Left/Center/Right/Stretch options
VerticalAlignment VerticalOptions Top/Center/Bottom/Stretch options

The actual interpretation of these properties depends on the parent container.

Layout views

WPF and Xamarin.Forms both use layout controls to position child elements. In most cases, these are very close to each other in terms of functionality.

WPF Xamarin.Forms Layout Style
StackPanel StackLayout Left-to-right, or top-to-bottom infinite stacking
Grid Grid Tabular format (rows and columns)
DockPanel n/a Dock to edges of window
Canvas AbsoluteLayout Pixel/Coordinate positioning
WrapPanel n/a Wrapping stack
n/a RelativeLayout Relative rule-based positioning

Xamarin.Forms does not support a GridSplitter.

Both platforms use attached properties to fine-tune children.

Rendering

The rendering mechanics for WPF and Xamarin.Forms are radically different. In WPF, the controls you create directly render content to pixels on the screen. WPF maintains two object graphs (trees) to represent this - the logical tree represents the controls as defined in code or XAML, and the visual tree represents the actual rendering that occurs on the screen which is performed either directly by the visual element (through a virtual draw method), or through a XAML-defined ControlTemplate which can be replaced or customized. Typically, the visual tree is more complex as it includes this such as borders around controls, labels for implicit content, etc. WPF includes a set of APIs (LogicalTreeHelper and VisualTreeHelper) to examine these two object graphs.

In Xamarin.Forms, the controls you define in a Page are really just simple data objects. They are similar to the logical tree representation, but never render content on their own. Instead, they are the data model which influences the rendering of elements. The actual rendering is done by a separate set of visual renderers which are mapped to each control type. These renderers are registered in each of the platform-specific projects by platform-specific Xamarin.Forms assemblies. You can see a list here. In addition to replacing or extending the renderer, Xamarin.Forms also has support for Effects which can be used to influence the native rendering on a per-plaform basis.

The Logical/Visual Tree

There is no exposed API to walk the logical tree in Xamarin.Forms - but you can use Reflection to get the same information. For example, here's a method which can enumerate logical children with reflection.

Graphics

Xamarin.Forms does not include a graphics system for primitives beyond a simple rectangle (BoxView). You can include 3rd party libraries such as SkiaSharp to get cross-platform 2D drawing, or UrhoSharp for 3D.

Resources

WPF and Xamarin.Forms both have the concept of resources and resource dictionaries. You can place any object type into a ResourceDictionary with a key and then look it up with {StaticResource} for things which will not change, or {DynamicResource} for things which can change in the dictionary at runtime. The usage and mechanics are the same with one difference: Xamarin.Forms requires that you define the ResourceDictionary to assign to the Resources property whereas WPF pre-creates one and assigns it for you.

For example, see the definition below:

WPF

<Window.Resources>
   <Color x:Key="redColor">#ff0000</Color>
   ...
</Window.Resources>

Xamarin.Forms

<ContentPage.Resources>
   <ResourceDictionary>
      <Color x:Key="redColor">#ff0000</Color>
      ...
   </ResourceDictionary>
</ContentPage.Resources>

If you do not define the ResourceDictionary, a runtime error is generated.

Styles

Styles are also fully supported in Xamarin.Forms and can be used to theme the Xamarin.Forms elements that make up the UI. They support triggers (property, event and data), inheritance through BasedOn, and resource lookups for values. Styles are applied to elements either explicitely through the Style property, or implicitely by not supplying a resource key - just like WPF.

Device Styles

WPF has a set of predefined properties (stored as static values on a set of static classes such as SystemColors) which dictate systme colors, fonts and metrics in the form of values and resource keys. Xamarin.Forms is similar, but defines a set of Device Styles to represent the same things. These styles are supplied by the frameowrk and set to values based on the runtime environment (e.g. accessibility).

WPF

<Label Text="Title" Foreground="{DynamicResource {x:Static SystemColors.DesktopBrushKey}}" />

Xamarin.Forms

<Label Text="Title" Style="{DynamicResource TitleStyle}" />

Control Templates

WPF supports the concept of Control Templates which provide the visualization instructions for a control (Button, ListBox, etc.). As mentioned above, Xamarin.Forms uses concrete rendering classes for this which interact with the native platform (iOS, Android, etc.) to visualize the control.

However, Xamarin.Forms does have a ControlTemplate type - it is used for theming Page objects. It provides a definition for a Page that provides consistent content, but allows the user of the page to change colors, fonts, etc. and even add elements to make it unique to the application.

Common usages for this are things such as authentication dialogs, prompts and to provide a standardized, but themable page look and feel that can be customized within the app. As part of this support, many familiar WPF-named controls are used:

  1. ContentPage
  2. ContentView
  3. ContentPresenter
  4. TemplateBinding

But it's important to know that these are not serving the same purpose in Xamarin.Forms. For more information on this feature, check out the documentation page.

XAML

XAML is used as the declarative markup language for WPF and Xamarin.Forms. For the most part, the syntax is identical - the primary difference is the objects that are defined/created by the XAML graphs.

  • Xamarin.Forms supports the XAML 2009 specification; this makes it easier to define data such as strings, ints, etc. as well as defining generic types and passing arguments to constructors.

  • There is currently no way to dyanmically load XAML like WPF can with XamlReader. You can get the same basic functionality with a NuGet package though.

Markup Extensions

Xamarin.Forms supports extending XAML through markup extensions, much like WPF. Out of the box, it has the same basic building blocks:

  1. {x:Array}
  2. {Binding}
  3. {DynamicResource}
  4. {x:Null}
  5. {x:Static}
  6. {StaticResource}
  7. {x:Type}

In addition, it includes {x:Reference} from the XAML 2009 specification, and a {TemplateBinding} markup extension which is used for the specialized version of ControlTemplate supported by Xamarin.Forms.

Note the ControlTemplate support isn't the same - even though it has the same name.

Xamarin.Forms supports custom markup extensions as well - but the implementation is slightly different. In WPF, you must derive from MarkupExtension - an abstract base class. In Xamarin.Forms, that is replaced with an interface IMarkupExtension or IMarkupExtension<T> which is more flexible.

Just like WPF, the single required method is a ProvideValue method to return the value from the markup extension.

Binding infrastructure

One of the core concepts carried over is a data binding infrastructure to connect visual properties to .NET data properties. This enables architectural patterns such as MVVM. The basic design is identical - you have a bindable base class BindableObject, in WPF this is the DependencyObject class. This base class is used as the root ancestor for all objects that will participate as targets in data binding. The derived classes then expose BindableProperty objects which act as the backing storage for property values (these are defined as DependencyProperty objects in WPF).

Defining bindable properties

The definition for a bindable property in Xamarin.Forms is the same as WPF:

  1. The object must derive from BindableObject.
  2. There must be a public static field of type BindableProperty declared to define the backing storage key for the property.
  3. There should be a public instance property wrapper that uses GetValue and SetValue to retrieve and change the properties value.

For a complete example, see Bindable Properties in Xamarin.Forms.

Attached properties

Attached properties are a subset of the bindable property and they work the same way they do in WPF. The primary difference is that the property wrapper is ommitted in this case and replaced with a set of static get/set methods on the owning class. See Attached Properties in Xamarin.Forms for more information.

Using the binding engine

The process for using the binding engine is the same as it is in WPF. It can be utilized in code-behind by creating a Binding object tied to a source object (any .NET type) and an optional property value (if ommitted, it treats the source object as the property itself - just like WPF). You can then use SetBinding on any BindableObject to associate the binding to a BindableProperty.

Alternatively, you can define the binding relationship in XAML using the BindingExtension. It has the same basic values as the extension in WPF.

The binding support and engine are more similar to the Silverlight implementation than WPF. There are several missing features which were not implemented in Xamarin.Forms:

  • There is no support for the following features in bindings:
    • BindingGroupName
    • BindsDirectlyToSource
    • IsAsync
    • MultiBinding
    • NotifyOnSourceUpdated
    • NotifyOnTargetUpdated
    • NotifyOnValidationError
    • UpdateSourceTrigger
    • UpdateSourceExceptionFilter
    • ValidatesOnDataErrors
    • ValidatesOnExceptions
    • ValidationRules collection
    • XPath
    • XmlNamespaceManager
  • Binding.Mode does not support OneTime, instead just use OneWay.

RelativeSource

There is no support for RelativeSource bindings. In WPF, these allow you to bind to other visual elements defined in XAML. In Xamarin.Forms, this same capability can be achieved using the {x:Reference} markup extension. For example, assuming we have a control with the name "otherControl" that has a Text property, we can bind to it like this:

WPF

Text={Binding RelativeSource={RelativeSource otherControl}, Path=Text}

Xamarin.Forms

Text={Binding Source={x:Reference otherControl}, Path=Text}

The same capability can be used for the {RelativeSource Self} feature. However there is no support for locating ancestors by type ({RelativeSource FindAncestor}).

Binding context

In WPF, you can define a DataContext property value which reprents the default binding source. If the source for a binding is not defined, this property value is used. The value is inherited down the visual tree, allowing it to be defined at a higher level and then used by children.

In Xamarin.Forms, this same feature is avaialable, but the property name is BindingContext.

Value converters

Value converters are fully supported in Xamarin.Forms - just like WPF. The same interface shape is used, but Xamarin.Forms has the interface defined in the Xamarin.Forms namespace.

Model-View-ViewModel

MVVM is completely supported by both WPF and Xamarin.Forms.

WPF includes a built in RoutedCommand which is sometimes used; Xamarin.Forms has no built-in commanding support beyond the ICommand interface definition. You can include a variety of MVVM frameworks to add the necessary base classes to implement MVVM.

INotifyPropertyChanged and INotifyCollectionChanged

Both interfaces are fully supported in Xamarin.Forms bindings. Unlike many XAML-based frameworks, property change notifications can be raised on background threads in Xamarin.Forms (just like WPF) and the binding engine will properly transition to the UI thread.

In addition, both environments support SynchronziationContext and async/await to do proper thread marshalling. WPF includes the Dispatcher class on all visual elements, Xamarin.Forms has a static method Device.BeginInvokeOnMainThread which can also be used (although SynchronizationContext is preferred for cross-platform coding).

  • Xamarin.Forms includes an ObservableCollection<T> which supports collection change notifications.
  • You can use BindingBase.EnableCollectionSynchronization to enable cross-thread updates for a collection. The API is slightly different from the WPF variation, check the docs for usage details.

Data Templates

Data templates are supported in Xamarin.Forms to customize the rendering of a ListView row (cell). Unlike WPF which can utilize DataTemplates for any content-oriented control, Xamarin.Forms currently only uses them for ListView. The template definition can be defined inline (assigned to the ItemTemplate property), or as a resource in a ResourceDictionary.

In addition, they are not quite as flexible as their WPF counterpart.

  1. The root element of the DataTemplate must always be a ViewCell object.
  2. Data Triggers are fully supported in a Data Template, but must include a DataType property indicating the type of the property that the trigger is associated with.
  3. DataTemplateSelector is also supported, but derives from DataTemplate and is therefore just assigned directly to the ItemTemplate property (vs. ItemTemplateSelector in WPF).

ItemsControl

There is no built-in equivelent to an ItemsControl in Xamarin.Forms; but there is a custom one for Forms available here.

User Controls

In WPF, UserControls are used to provide a section of UI which has associated behavior. In Xamarin.Forms, we use the ContentView for the same purpose. Both support binding and inclusion in XAML.

Navigation

WPF includes a rarely used NavigationService which could be used to provide a "browser-like" navigation feature. Most apps didn't bother with this however and instead used different Window elements, or different sections of the window to display data.

On phone devices, different screens are often the solution and so Xamarin.Forms includes support for several forms of navigation:

Navigation Style Page Type
Stack-based (push/pop) NavigationPage
Master/Detail MasterDetailPage
Tabs TabbedPage
Swipe Left/Right CarouselView

The NavigationPage is the most common approach, and every page has a Navigation property which can be used to push or pop pages on and off the navigation stack. This is the closest equivelent to the NavigationService found in WPF.

URL navigation

WPF is a desktop-oriented technology and can accept command-line parameters to direct startup behavior. Xamarin.Forms can use deep URL linking to jump to a page on startup.

Common APIs

Purpose WPF Xamarin.Forms
Display a message on the screen with buttons MessageBox Page.DisplayAlert
Create a timer DispatcherTimer class Device.StartTimer static method
Get a default font size SystemFonts static class Device.GetNamedSize static method
Open a URI/URL Process.Start Device.OpenUri
Display action sheet (list of buttons) n/a Page.DisplayActionSheet
@santoshdengale
Copy link

Nice

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment