WPF (Windows Presentation Foundation) is Microsoft's recommended presentation technology for classic Windows desktop applications. WPF should not be confused with UWP (Universal Windows Platform) although similarities exist between the two.
WPF encourages data driven applications with a strong focus on multimedia, animation and data binding. Interfaces are created using a language called XAML (eXtensible Application Markup Language), a derivative of XML. XAML helps WPF programmers maintain separation of visual design and interface logic.
Unlike its predecessor Windows Forms, WPF uses a box model to layout all elements of the interface. Each element has a Height, Width and Margins and is arranged on screen relative to it's parent.
WPF stands for Windows Presentation Foundation and is also known under its Codename Avalon. It's a graphical Framework and part of Microsofts .NET Framework. WPF is pre-installed in Windows Vista, 7, 8 and 10 and can be installed on Windows XP and Server 2003.
Models and View-Models
The definition of a model is often hotly debated, and the line between a model and a view-model can be blurred. Some prefer not to "pollute" their models with the INotifyPropertyChanged
interface, and instead duplicate the model properties in the view-model, which does implement this interface. Like many things in software development, there is no right or wrong answer. Be pragmatic and do whatever feels right.
View Separation
The intention of MVVM is to separate those three distinct areas - Model, view-model, and View. While it's acceptable for the view to access the view-model (VM) and (indirectly) the model, the most important rule with MVVM is that the VM should have no access to the view or its controls. The VM should expose everything that the view needs, via public properties. The VM should not directly expose or manipulate UI controls such as TextBox
, Button
, etc.
In some cases, this strict separation can be difficult to work with, especially if you need to get some complex UI functionality up and running. Here, it's perfectly acceptable to resort to using events and event handlers in the view's "code-behind" file. If it's purely UI functionality then by all means utilise events in the view. It's also acceptable for these event handlers to call public methods on the VM instance - just don't go passing it references to UI controls or anything like that.
RelayCommand
Unfortunately the RelayCommand
class used in this example isn't part of the WPF framework (it should have been!), but you'll find it in almost every WPF developer's tool box. A quick search online will reveal plenty of code snippets that you can lift, to create your own.
A useful alternative to RelayCommand
is ActionCommand
which is provided as part of Microsoft.Expression.Interactivity.Core
which provides comparable functionality.
By default, WPF updates the binding source when the control loses focus. However, if there is only one control that can get focus -- something that's common in examples -- you will need to specify UpdateSourceTrigger=PropertyChanged
for the updates to work.
You will want want to use PropertyChanged
as the trigger on many two-way bindings unless updating the binding source on every keystroke is costly or live data validation is undesirable.
Using LostFocus
has an unfortunate side effect: pressing enter to submit a form using a button marked IsDefault
does not update the property backing your binding, effectively undoing your changes. Fortunately, some workarounds exist.
Please also note that, unlike UWP, WPF (4.5+) also has the Delay
property in bindings, wich might just be enough for some Bindings with local-only or simple minor intelligence settings, like some TextBox
validations.
Content of controls can be localized using Resource files, just as this is possible in classes. For XAML there is a specific syntax, that is different between a C# and a VB application.
The steps are:
PublicVbMyResourcesResXFileCodeGenerator
.IValueConverter and IMultiValueConverter - interfaces that provides a way to apply a custom logic to a binding.
These are some of the simple cases, but there are many more.
For cases like this, you can use a value converter. These small classes, which implement the IValueConverter interface or IMultiValueConverter, will act like middlemen and translate a value between the source and the destination. So, in any situation where you need to transform a value before it reaches its destination or back to its source again, you likely need a converter.
In WPF, a Style defines the values of one or more dependency properties for a given visual element. Styles are used throughout the application to make the user interface more consistent (e.g. giving all dialog buttons a consistent size) and to make bulk changes easier (e.g. changing the width of all buttons.)
Styles are typically defined in a ResourceDictionary
at a high level in the application (e.g. in App.xaml or in a theme) so it is available app-wide, but they may also be defined for a single element and its children, e.g. applying a style to all TextBlock
elements inside a StackPanel
.
<StackPanel>
<StackPanel.Resources>
<Style TargetType="TextBlock">
<Setter Property="Margin" Value="5,5,5,0"/>
<Setter Property="Background" Value="#FFF0F0F0"/>
<Setter Property="Padding" Value="5"/>
</Style>
</StackPanel.Resources>
<TextBlock Text="First Child"/>
<TextBlock Text="Second Child"/>
<TextBlock Text="Third Child"/>
</StackPanel>
StaticResource
. In other words, if you're defining a style that depends upon another style or resource in a resource dictionary, it must be defined after/below the resource upon which it depends.StaticResource
is the recommended way to reference styles and other resources (for performance and behavioral reasons) unless you specifically require the use of DynamicResource
, e.g. for themes that can be changed at runtime.MSDN has thorough articles on styles and resources that have more depth than is possible to provide here.
Note that a UserControl is very different from a Control. One of the primary differences is that a UserControl makes use of a XAML layout file to determine where to place several individual Controls. A Control, on the other hand, is just pure code - there's no layout file at all. In some ways, creating a custom Control can be more effective than creating a custom UserControl.
A markup extension can be implemented to provide values for properties in an attribute usage, properties in a property element usage, or both.
When used to provide an attribute value, the syntax that distinguishes a markup extension sequence to a XAML processor is the presence of the opening and closing curly braces ({ and }). The type of markup extension is then identified by the string token immediately following the opening curly brace.
When used in property element syntax, a markup extension is visually the same as any other element used to provide a property element value: a XAML element declaration that references the markup extension class as an element, enclosed within angle brackets (<>).
For more info visit https://msdn.microsoft.com/en-us/library/ms747254(v=vs.110).aspx
A key point to note, which is not obvious from the documentation, and you could go for years without knowing is that it defaults to behaving like InternetExplorer7, rather than your most up-to-date InternetExplorer installation (see https://weblog.west-wind.com/posts/2011/may/21/web-browser-control-specifying-the-ie-version ).
This cannot be fixed by setting a property on the control; you must either modify the pages being displayed by adding an HTML Meta Tag, or by applying a registry setting(!). (Details of both approaches are on the link above.)
For example, this bizarre design behaviour might lead you to get a message saying "Script Error"/"An error has occurred in the script on this page". Googling this error might make you think that the solution is to try to suppress the error, rather that understanding the actual problem, and applying the correct solution.
EventTrigger
must be defined within a <Style>
element. An EventTrigger
may be defined in either a <Style>
element, or a control's Triggers
property.<Trigger>
elements may contain any number of <Setter>
elements. These elements are responsible for setting properties on the containing element when the <Trigger>
element's condition is met.<Setter>
element will not take effect, even if the trigger condition has been met. Consider the markup <TextBlock Text="Sample">
. The Text
property of the proceeding code will never change based on a trigger because root property definitions take precidence over properties defined in styles.