Hidden features of WPF and XAML?
Asked Answered
E

25

123

Here is a large number of hidden features discussed for variety of languages. Now I am curious about some hidden features of XAML and WPF?

One I have found is the header click event of a ListView

<ListView x:Name='lv' 
      Height="150" 
      GridViewColumnHeader.Click="GridViewColumnHeaderClickedHandler">

The GridViewColumnHeader.Click property is not listed.

Some of relevant features so far:

See also:

  1. Hidden features of C#
  2. Hidden features of Python
  3. Hidden features of ASP.NET
  4. Hidden features of Perl
  5. Hidden features of Java
  6. Hidden features of VB.NET
  7. Hidden features of PHP
  8. Hidden features of Ruby
  9. Hidden features of C
  10. And So On........
Enact answered 14/7, 2009 at 11:20 Comment(4)
Have a look here msdn.microsoft.com/en-us/library/… . The click event is inherited from ButtonBase. What you are describing are attached Events, a pretty powerfull concept in WPF (msdn.microsoft.com/en-us/library/bb613550.aspx). This way you can do <Grid Button.Click> with 100 buttons on a grid and only 1 handler.Boar
At first I was like "oh, here we go again," but then I learned something in the responses so I take it all back :o :oPenitentiary
should be community wikiHostetter
@Hostetter I don't think it should be community wiki, have look at this link meta.stackexchange.com/questions/392/…Damage
S
87

Multibinding (combined with StringFormat):

<TextBlock>
  <TextBlock.Text>
    <MultiBinding StringFormat="{}{0}, {1}">
      <Binding Path="LastName" />
      <Binding Path="FirstName" />
    </MultiBinding>
  </TextBlock.Text>
</TextBlock>
Semiology answered 14/7, 2009 at 11:20 Comment(2)
awesome :-) unless you're using silverlight 4 or earlier. fingers crossed for v5Tetrahedral
This is great, but I'd be tempted NOT to do it. If I need to build a string, I'd class that as logic and would want to unit test the output. Stuff like this is sometimes better off in the view model as a string.Format().Liverpool
E
58

There is also PresentationTraceSources.TraceLevel trick to debug what is going on with bindings in any particular scenario. All you have to do is to reference System.Diagnostics namespace in WindowsBase assembly

xmlns:sd="clr-namespace:System.Diagnostics;assembly=WindowsBase"

and then add following to the binding expression:

<TextBlock Text="{Binding Message, sd:PresentationTraceSources.TraceLevel=High}"  />

Log will be like this:

System.Windows.Data Warning: 52 : Created BindingExpression (hash=5923895) for Binding (hash=7588182)
System.Windows.Data Warning: 54 :   Path: 'Message'
System.Windows.Data Warning: 56 : BindingExpression (hash=5923895): Default mode resolved to OneWay
System.Windows.Data Warning: 57 : BindingExpression (hash=5923895): Default update trigger resolved to PropertyChanged
System.Windows.Data Warning: 58 : BindingExpression (hash=5923895): Attach to System.Windows.Controls.TextBlock.Text (hash=65248697)
System.Windows.Data Warning: 63 : BindingExpression (hash=5923895): Resolving source 
Effector answered 14/7, 2009 at 11:20 Comment(1)
In VisualStudio 2010 you need to set the level of the trace settings to warning! See #2803162Tracheitis
F
44

3.5sp1 introduced TargetNullValue to bindings. This will set the bound property to Null if the value is entered and if your property is Null it will display this value.

<TextBox Text="{Binding Total, TargetNullValue=$0.00}" />
Foti answered 14/7, 2009 at 11:20 Comment(0)
F
44

3.5sp1 introduced StringFormat into binding expressions, e.g.

<TextBox Text="{Binding Date, StringFormat='{}{0:MM/dd/yyyy}'}" />
Foti answered 14/7, 2009 at 11:20 Comment(6)
I can't put into words just how much I love that feature. I hated having tons of value converters laying around.Hobble
Yeah, easily one of the most time saving features added. Especially when combined with TargetNullValue a lot of problems go away.Foti
Putting single quotes around the StringFormat should remove some compiler warnings - Text={Binding Date, StringFormat='{}{0:MM/dd/yyyy}'}"Wiburg
Good to know, I've gotten used to just ignoring them.Foti
Can someone give an example of this that follows internationalization recommendations? I'm pretty sure date formats shouldn't be hard coded like that.Pottle
I was trying to convey that any arbitrary formatting string will work. I believe the internationalized version would be StringFormat='{}{0:d}' in this case.Foti
T
29

Sometimes you get string that is too long to show on label. In this case we can make use of TextTrimming property of TextBlock to show Ellipses

<TextBlock 
  Name="sampleTextBlock" 
  TextTrimming="WordEllipsis" 
  TextWrapping="NoWrap"/>

MSDN Link

Tartaglia answered 14/7, 2009 at 11:20 Comment(1)
Consider adding a tooltip in such case: tranxcoder.wordpress.com/2008/10/12/…Everett
E
27

Adding Aero effect to Window

  <Window.Resources>
    <ResourceDictionary Source="/PresentationFramework.Aero, Version=3.0.0.0, Culture=neutral, 
        PublicKeyToken=31bf3856ad364e35, ProcessorArchitecture=MSIL;component/themes/aero.normalcolor.xaml" />
</Window.Resources>
Enact answered 14/7, 2009 at 11:20 Comment(1)
Added the code but still doesn't adds the Aero effect. Am I missing something?Valera
E
21

Generics in XAML with x:TypeArguments

If you want to use an ObservableCollection in XAML you need to create a type that derives from ObservableCollection because you cannot declare it in XAML. With XAML 2009 you can use the x:TypeArguments attribute to define the type of a generic type.

<!-- XAML 2006 -->
class EmployeeCollection : ObservableCollection<Employee>
{
}

<l:EmployeeCollection>
    <l:Employee FirstName="John" Name="Doe" />
    <l:Employee FirstName="Tim" Name="Smith" />
</lEmployeeCollection>

<!-- XAML 2009 -->
<ObservableCollection x:TypeArguments="Employee">
    <l:Employee FirstName="John" Name="Doe" />
    <l:Employee FirstName="Tim" Name="Smith" />
</ObservableCollection />
Enact answered 14/7, 2009 at 11:20 Comment(2)
Unfortunately, x:TypeArguments is only available in loose xaml files and not compiled ones :(Zoogloea
Yep, loose xaml only :( For majority of WPF developers XAML2009 is useless.Billmyre
E
19

Use of Non-Default Constructors with x:Arguments

In XAML 2006 objects must have a public default constructor to use them. In XAML 2009 you can pass constructor arguments by using the x:Arguments syntax.

<!-- XAML 2006 -->
<DateTime>00:00:00.0000100</DateTime>

<!-- XAML 2009 -->
<DateTime>
    <x:Arguments>
        <x:Int64>100</x:Int64>
    </x:Arguments>
</DateTime>
Enact answered 14/7, 2009 at 11:20 Comment(0)
E
19

Show Tooltip on a disabled control

Wpf allows to show tooltip on a control, if it is in disabled state.

For example

<Button Content="Disabled Button" ToolTipService.ShowOnDisabled="True" IsEnabled="False" ToolTip="This is a disabled button"/> 
Enact answered 14/7, 2009 at 11:20 Comment(0)
M
18

Markup extensions and attached properties are my favorite features, they enable you to extend XAML "vocabulary" in a very elegant way.

Markup extensions

<!-- Binding to app settings -->
<CheckBox IsChecked="{my:SettingBinding MinimizeToTray}">Close to tray</CheckBox>

<!-- Fill ItemsControl with the values of an enum -->
<ComboBox ItemsSource="{my:EnumValues sys:DaysOfWeek}"/>

<!-- Localization -->
<TextBlock Text="{my:Localize HelloWorld.Text}"/>

<!-- Switch on the result of a binding -->
<TextBlock Text="{my:Switch Path=IsGood, ValueIfTrue=Good, ValueIfFalse=Bad}"/>

Attached properties

<!-- Sort GridView automatically -->
<ListView ItemsSource="{Binding Persons}"
      IsSynchronizedWithCurrentItem="True"
      util:GridViewSort.AutoSort="True">
    <ListView.View>
        <GridView>
            <GridView.Columns>
                <GridViewColumn Header="Name"
                                DisplayMemberBinding="{Binding Name}"
                                util:GridViewSort.PropertyName="Name"/>
                <GridViewColumn Header="First name"
                                DisplayMemberBinding="{Binding FirstName}"
                                util:GridViewSort.PropertyName="FirstName"/>
                <GridViewColumn Header="Date of birth"
                                DisplayMemberBinding="{Binding DateOfBirth}"
                                util:GridViewSort.PropertyName="DateOfBirth"/>
            </GridView.Columns>
        </GridView>
    </ListView.View>
</ListView>


<!-- Vista Glass effect -->
<Window x:Class="WpfApplication1.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:my="clr-namespace:WpfApplication1"
        Title="Window1"
        my:WinUtil.EnableAeroGlass="True">

...

Source for GridViewSort (btw, it uses the GridViewColumnHeader.Click event mentioned by Ortus)

Microhenry answered 14/7, 2009 at 11:20 Comment(2)
Is the source for WinUtil.EnableAeroGlass available somewhere?Spoondrift
Yes, but it has changed a lot since I posted this... There are now 2 properties, EnableBlur and GlassFrameMargins. You can find the code here : projets.developpez.com/projects/dvp-net/repository/entry/trunk/…Microhenry
F
18

Not really a hidden feature but with WPF/XAML you get Bea Stollnitz and Josh Smith. Queen and King of WPF/XAML programming.

Foti answered 14/7, 2009 at 11:20 Comment(1)
What is Karl? The Jack? Or the Joker?Gaiser
I
15

You can refer to nested types in XAML using the plus sign (+). For example, if we had this class:

public class SomeClass
{
    public enum SomeEnum
    {
        SomeValue
    };
}

We could refer to SomeValue in XAML using the following syntax:

{x:Static local:SomeClass+SomeEnum.SomeValue}

This syntax is not documented on MSDN, and it is not officially supported. Someone asked about it on the MSDN forums, and apparently it breaks VS2010's WPF Designer. It has been reported on Microsoft Connect.

Interregnum answered 14/7, 2009 at 11:20 Comment(0)
F
14

Grid size sharing (here's a good example). Long story short you can have grid columns and rows share sizes, even across different grids. This will be invaluable for all the people out there who are using DataGrids without the need to edit the data in place.

Foti answered 14/7, 2009 at 11:20 Comment(0)
P
11

PriorityBinding. Allows you to use asyn bindings in an "first come first show" order:

<TextBlock.Text>
      <PriorityBinding FallbackValue="defaultvalue">
        <Binding Path="SlowestDP" IsAsync="True"/>
        <Binding Path="SlowerDP" IsAsync="True"/>
        <Binding Path="FastDP" />
      </PriorityBinding>
</TextBlock.Text>
Photogenic answered 14/7, 2009 at 11:20 Comment(0)
E
10

Use of Static Factory Methods with x:FactoryMethod

When you have a type that has no public constructor but a static factory method you had to create that type in code in XAML 2006. With XAML 2009 you can use the x:FactoryMethodx:Arguments attribute to pass the argument values.

<!-- XAML 2006 -->
Guid id = Guid.NewGuid();

<!-- XAML 2009 -->
<Guid x:FactoryMethod="Guid.NewGuid" />
Enact answered 14/7, 2009 at 11:20 Comment(0)
E
7

XAML Converters

The following list shows converters developed by the WPF community to convert different formats to XAML or vice versa.

Adobe Illustrator XAML Export Plugin

Adobe Photoshop to XAML Converter

Blender XAML Export Plugin

Lightwave XAML Export Plugin

Visio XAML Export

3D Studio Max to XAML Converter

Maya to XAML Converter

Flash to XAML Converter

SVG to XAML Converter

WMF/EMF to XAML Converter

Enact answered 14/7, 2009 at 11:20 Comment(1)
also very useful: GridLengthConverter, BooleanToVisibilityConverter, AlternationConverter all in System.Windows.ControlsDeanedeaner
A
7

Advanced "caption" properties

Another thing that is not very clear is the contents of some properties that we are used to contains only text. If the property of a GUI element is of type Object, it is very likely that you can, instead of just setting the text, add a panel of your need that includes a set of controls.

An example of this is the MenuItem, where the Header property (which normally just contains text) can contain a set of gui elements wrapped in a panel control (or just one gui element if you need just one).

Also note the Icon property on the MenuItem. This normally contains an Image element, but this also can contain anything!

<MenuItem Name="MyMenuItem" Click="MyMenuItem_Click">
  <MenuItem.Icon>
    <Button Click="Button1_Click">i</Button>
  </MenuItem.Icon>
  <MenuItem.Header>
     <StackPanel Orientation="Horizontal" >
        <Label>My text</Label>
        <Button Click="Button2_Click">ClickMe!</Button>
     </StackPanel>
  </MenuItem.Header>
</MenuItem>
Aqaba answered 14/7, 2009 at 11:20 Comment(0)
A
6

System Colors Usage

<Border Background="{DynamicResource {x:Static SystemColors.InactiveBorderBrushKey}}"/>
Artimas answered 14/7, 2009 at 11:20 Comment(1)
Specifying it as a DynamicResource is important because the user can change the system colors while your application is running.Linesman
E
6

Easy Object References with {x:Reference}

If you want to create an object reference today you need to do a databinding and declare the source with an ElementName. In XAML 2009 you can use the new {x:Reference} markup extension

<!-- XAML 2006 -->
<Label Target="{Binding ElementName=firstName}">FirstName</Label>
<TextBox x:Name="firstName" />

<!-- XAML 2009 -->
<Label Target="{x:Reference firstName}">FirstName</Label>
<TextBox x:Name="firstName" />
Enact answered 14/7, 2009 at 11:20 Comment(2)
It's worth noting that while x:Reference is a XAML 2009 language feature, there are some scenarios where it will work in compiled XAML as well. However, it doesn't work everywhere, and it may break the XAML designer view.Delative
@MikeStrobel: It works pretty much everywhere, aaand i couldn't care less about designers breaking.Elliottellipse
E
6

Built-in Types

If you want to add objects of simple types like string or double to a resource dictionary today you need to map the needed clr-namespaces to an XML namespaces. In XAML 2009 we a lot of simple types that are included in the XAML language.

<!-- XAML 2006 -->
<sys:String xmlns:sys="clr-namespace:System;assembly=mscorlib >Test</sys:String>

<!-- XAML 2009 -->
<x:String>Test</x:String>

The following types are included into the XAML language:

<x:Object/> 
<x:Boolean/> 
<x:Char/> 
<x:String/> 
<x:Decimal/> 
<x:Single/> 
<x:Double/> 
<x:Int16/> 
<x:Int32/> 
<x:Int64/> 
<x:TimeSpan/> 
<x:Uri/> 
<x:Byte/> 
<x:Array/> 
<x:List/> 
<x:Dictionary/> 
Enact answered 14/7, 2009 at 11:20 Comment(1)
This does not work if using WPF to process XAML. msdn.microsoft.com/en-us/library/ee792007.aspxTenebrae
E
3

Support for Arbitrary Dictionary Keys

In XAML 2006 all explicit x:Key value were treated as strings. In XAML 2009 you can define any type of key you like by writing the key in ElementSyntax.

<!-- XAML 2006 -->
<StreamGeometry x:Key="CheckGeometry">M 0 0 L 12 8 l 9 12 z</StreamGeometry>

<!-- XAML 2009 -->
<StreamGeometry>M 0 0 L 12 8 l 9 12 z
    <x:Key><x:Double>10.0</x:Double></x:Key>
</StreamGeometry>
Enact answered 14/7, 2009 at 11:20 Comment(0)
G
2

The Ability to Stuff UIElement(s) into a TextBlock

I don't know how useful (it qualifies as hidden though) this is ... but it sure caught me off-guard when I first ran into it:

<Grid x:Name="LayoutRoot">
    <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center">
        <Grid>
            <Rectangle Fill="AliceBlue" Width="25" Height="25"/>
        </Grid>
    </TextBlock>
</Grid>

You could argue the following xaml could be useful (i.e. putting a graphic at the end of some text):

<Grid>
    <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="Hello World">
        <TextBlock.Resources>
            <DrawingBrush x:Key="exclamationPoint" Stretch="Uniform">
                <DrawingBrush.Drawing>
                    <DrawingGroup>
                        <DrawingGroup.Children>
                            <GeometryDrawing Brush="#FF375CE2" Geometry="F1 M 7.968,58.164L 0,58.164L 1.914,49.921L 9.882,49.921L 7.968,58.164 Z M 21.796,0L 11.054,42.148L 4.403,42.148L 13.049,0L 21.796,0 Z "/>
                        </DrawingGroup.Children>
                    </DrawingGroup>
                </DrawingBrush.Drawing>
            </DrawingBrush>
        </TextBlock.Resources>
        <Grid>
            <Rectangle Width="100" Height="100" Fill="{StaticResource exclamationPoint}"/>
        </Grid>
    </TextBlock>
</Grid>

The above xaml renders like the following:

Hello World

Gaiser answered 14/7, 2009 at 11:20 Comment(0)
E
2

Set a ValidationError by Code

A ValidatioRule in a BindingExpression only triggers, when the target side of the binding changes. If you want to set a validation error by code you can use the following snippet.

Set the validation error

ValidationError validationError = 
    new ValidationError(regexValidationRule, 
    textBox.GetBindingExpression(TextBox.TextProperty));

validationError.ErrorContent = "This is not a valid e-mail address";

Validation.MarkInvalid(
    textBox.GetBindingExpression(TextBox.TextProperty), 
    validationError);

Clear the validation error

Validation.ClearInvalid(textBox.GetBindingExpression(TextBox.TextProperty));
Enact answered 14/7, 2009 at 11:20 Comment(0)
T
1

Binding without INotifyPropertyChanged or DependencyProperties

As discussed here you can bind a plain CLR object property without INotifyPropertyChanged, and it will just work.

Here is the Forumpost i am referring to.

Quote:

[...] WPF's data binding engine will data bind to PropertyDescriptor instance which wraps the source property if the source object is a plain CLR object and doesn't implement INotifyPropertyChanged interface. And the data binding engine will try to subscribe to the property changed event through PropertyDescriptor.AddValueChanged() method. And when the target data bound element change the property values, data binding engine will call PropertyDescriptor.SetValue() method to transfer the changed value back to the source property, and it will simultaneously raise ValueChanged event to notify other subscribers (in this instance, the other subscribers will be the TextBlocks within the ListBox.

And if you are implementing INotifyPropertyChanged, you are fully responsible to implement the change notification in every setter of the properties which needs to be data bound to the UI. Otherwise, the change will be not synchronized as you'd expect.[...]

Here is another great and detailed article on the subject.

Note this only works when using binding. If you update the values from code, the change won't be notified. [...]

Implementing INotifyPropertyChanged can be a fair bit of tedious development work. However, you'll need to weigh that work against the runtime footprint (memory and CPU) of your WPF application. Implementing INPC yourself will save runtime CPU and memory.

Tiling answered 14/7, 2009 at 11:20 Comment(0)
E
1

Debugging Animations

Common Errors

If you get the following error: Cannot animate '(0).(1)' on an immutable object instance. it could be that you are run into one of the following limitations:

  • You are animating a dependency property without setting a local value
  • You are animating a dependency property who's current value is defined in another assembly that is not merged into the resource dictionary.
  • You are animating a value that is currently databound
Enact answered 14/7, 2009 at 11:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.