Click here to Skip to main content
Email Password   helpLost your password?

Introduction

Over the past year I have been playing and working with WPF, and have published a few articles (though not as good as Josh Smiths / Karl Shiffletts) on WPF. As such there have been a few questions/comments/queries posted in the forums attached to these articles. One of the most common questions/puzzlements I see is that people seem to be honestly lost by the differences between doing something in XAML opposed to doing something in code (C# | VB .NET), and how the heck content works. I recall one of codeprojects greatest authors, Marc Clifton being particularly frustrated about Content, and Marc has actually created his own declarative XML markup MyXaml. So when someone like that is getting frustrated it must be confusing.

This article will attempt to outline several areas that people seem to struggle with the most (based on the questions I have been asked in my own articles). I hope that

That's the plan at any rate  


Contents

Here is what I will be covering in this article


Pre-Requisites

In order to get the most out of this article, I would suggest you download the free .NET Dissambler, Reflector, which is freely available using the new Redgate download page. Redgate recently took over development of this product from Lutz Roeder. So thanks Lutz, it is, and always has been a great product.


Content Weirdness

If we consider the following section of XAML

<Window x:Class="WPF_Mysteries.Window2"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window2" Height="300" Width="300">
    <StackPanel Orientation="Vertical">
        <Button Background="Aqua" Margin="10" Width="Auto" Content="1" />
        <Button Background="Green" Margin="10" Width="Auto" Content="2" />
        <Button Background="Pink" Margin="10" Width="Auto" Content="3" />
    </StackPanel>
</Window>

We can see that this produces the following screenshot

But how does this work. Is it magic? Well actually no. If we go and look up a StackPanel in Reflector, and have a look at its definition.

This doesn't tell us too much, but we can see that this inherits from Panel, which in turn looks like the following

What is very interesting here, is an attribute, namely the ContentPropertyAttribute, which here is shown as being Children. Also worth a mention is the interface IAddChild. MSDN states the following, IAddChild provides a means to parse elements which permit child elements or text. The main use of IAddChild is to support FrameworkElementFactory.

For purposes of establishing or defining a content property or content model, IAddChild is obsolete. Apply the ContentPropertyAttribute to a custom class instead.

Ok so Panel has both a ContentPropertyAttribute and implements IAddChild. If we look at the Children property, which is a GET only property, as shown below

We can see that we can use this to obtain a UIElementCollection which is what is used to add child UIElements to. Panel actually also uses IAddChild behind the scenes, which as we can see below it does

Which as we can see is where the real work of adding objects to the internal Children property of Panel.


These are the only methods within the IAddChild interface.

So that is how some of the standard System.Windows.Controls, that support children (such as Grid/StackPanel/Canvas etc etc), deal with content. However if the control is supposed to have a single piece of Content, you will find that it still implements the IAddChild interface and has a Content property much the same as described above. This is shown below for the System.Windows.Controls.Label control, which in turn inherits from System.Windows.Controls.ContentControl.

In order to demonstrate the ContentPropertyAttribute further let's soldier on and try and get to the bottom of the magical content property. I have a small UserControl that I have declared as follows:

<UserControl x:Class="WPF_Mysteries.ContentTestControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Height="auto" Width="auto">
    <StackPanel Orientation="Vertical">
        <Label Content="There are currently"/>
        <Label Content="{Binding SomeContent.Count}"/>
        <Label Content="elements, on the SomeContent property"/>
    </StackPanel>
 
</UserControl>

And here is the related C# code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Windows.Markup;
using System.Collections.ObjectModel;

namespace WPF_Mysteries
{
    /// <summary>
    /// This demonstrates how to use the ContentPropertyAttribute, which is 
    /// how some of the native Controls such as Grid/Canvas/StackPanel etc etc
    /// know what to do with the content that is added to them in XAML.
    /// Basically the ContentPropertyAttribute, tells the XAML parser, 
    /// what code behind property should be used when the XAML parser 
    /// finds some content.
    /// </summary>
    [ContentProperty("SomeContent")]
    public partial class ContentTestControl : UserControl
    {
        #region Public Properties
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public ObservableCollection<UIElement> SomeContent { get; set; }
        #endregion

        #region Ctor
        public ContentTestControl()
        {
            InitializeComponent();
            SomeContent = new ObservableCollection<UIElement>();
            // Allows binding to it's own properties
            this.DataContext = this;
        }
        #endregion
    }
}

I then use this ContentTestControl control within a XAML Window as follows. Notice that I am actually adding 4 controls here, but I do not tell it what property I am using to add these controls to. This is done via the magic of the ContentPropertyAttribute, which is pointing to the ContentTestControl.SomeContent property. The XAML parser knows what to do with these 4 controls, they are simply added to the ContentTestControl.SomeContent property (which is after all a ObservableCollection<UIElement>, so should support Adds, it's a collection is it not!).

<local:ContentTestControl x:Name="testControl">
    <StackPanel Orientation="Vertical">
        <Label>one</Label>
        <Label>two</Label>
    </StackPanel>
    <StackPanel Orientation="Vertical">
        <Label>3</Label>
        <Label>4</Label>
    </StackPanel>
    <StackPanel Orientation="Vertical">
        <Label>5</Label>
        <Label>6</Label>
    </StackPanel>
    <StackPanel Orientation="Vertical">
        <Label>7</Label>
        <Label>8</Label>
    </StackPanel>
</local:ContentTestControl>

Which results in the following screen shot. It should however be noted that since my ContentTestControl UserControl inherits from UserControl it is UserControl that actually adds the elements as actual UI elements, which is why we are seeing different UIElements, within the screenshort than you might have thought. You may have been expecting to see the 4 * StackPanelShown above. But the ContentTestControl.SomeContent is really just a property that is holding the values specified by the ContentPropertyAttribute, it doesnt nessecarily do anything with these values. In the standard System.Windows.Controls controls, the Content property probably would affect the UI as well.

It can be seen from this screenshot that the Binding that was set up in the ContentTestControl (where the ContentTestControl.xaml has the Binding set as follows {Binding SomeContent.Count}) shows a result of 4. This is interesting since the ContentTestControl didn't use the IAddChild interface at all, but still worked just fine, this is all thanks to the ContentPropertyAttribute usage on this class.


Creating Styles/Templates In Code

One thing that seems to crop up over and over again, is people really don't know how to create  Styles or templates in code. Obviously XAML is better suited to doing this than code, so why the hell would you want to do this in code anyway. Well consider a system which is quite dynamic, and may be driven by meta driven objects, where what objects and properties you may be using are not known at design time. I am actually working on a system like this right now, where everything (most screens) are driven by metadata, where the metadata contains crucial information about the objects the metadata is associated with.

So the system is quite dynamic, so statically declared Styles or templates just don't cut the mustard, so we have to create them in code. I am not saying this is normal, but I have been asked how to do this enough times to warrant a small rant on the subject. So consider the following section a small rant on how to create Template/Styles in code.

Creating Styles In Code

Let's start with a simple example, suppose I have the following Style, declared in XAML, which is applied to ListBoxItems.

<ListBox.ItemContainerStyle>
    <!-- And how about a nice simple Style for a ListBoxItem -->
    <Style TargetType="ListBoxItem">
        <Setter Property="TextElement.FontSize" Value="14"/>

        <Style.Triggers>
            <Trigger Property="IsMouseOver" Value="true">
                <Setter Property="Foreground" Value="Black" />
                <Setter Property="Background">

                    <Setter.Value>

                        <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">

                            <LinearGradientBrush.GradientStops>
                                <GradientStop Color="#0E4791" Offset="0"/>
                                <GradientStop Color="#468DE2" Offset="1"/>
                            </LinearGradientBrush.GradientStops>
                        </LinearGradientBrush>

                    </Setter.Value>
                </Setter>
                <Setter Property="Cursor" Value="Hand"/>
            </Trigger>
        </Style.Triggers>

    </Style>
</ListBox.ItemContainerStyle>

I think this is pretty self explanatory. But how about the code equivalent

//And here is the C# code to achieve the above
Style styleListBoxItem = new Style(typeof(ListBoxItem));
styleListBoxItem.Setters.Add(new Setter
{
    Property=TextElement.FontSizeProperty,
    Value=14.0
});

//Trigger
Trigger triggerIsMouseOver  = 
    new Trigger { Property=ListBoxItem.IsMouseOverProperty, Value=true };

triggerIsMouseOver.Setters.Add(new Setter(ListBoxItem.ForegroundProperty, Brushes.Black));

GradientStopCollection gradientStopsLinearBrush = new GradientStopCollection();
gradientStopsLinearBrush.Add(
    new GradientStop((Color)ColorConverter.ConvertFromString("#0E4791"), 0.0));
gradientStopsLinearBrush.Add(
    new GradientStop((Color)ColorConverter.ConvertFromString("#468DE2"), 1.0));

LinearGradientBrush backgroundLinearBrush = 
    new LinearGradientBrush(gradientStopsLinearBrush)
{
    StartPoint = new Point(0,0),
    EndPoint = new Point(0,1)
};

//Trigger setters
triggerIsMouseOver.Setters.Add(
    new Setter(ListBoxItem.BackgroundProperty, backgroundLinearBrush));
triggerIsMouseOver.Setters.Add(
    new Setter(ListBoxItem.CursorProperty, Cursors.Hand));
styleListBoxItem.Triggers.Add(triggerIsMouseOver);

As you can see for Styles, there is pretty much a 1 to 1 mapping to the XAML code, it's not that bad really. The only thing worth a mention is the part where we have a XAML Setter, which looks like the following

<ListBox.ItemContainerStyle>
    <!-- And how about a nice simple Style for a ListBoxItem -->
    <Style TargetType="ListBoxItem">
	....
                <Setter Property="Cursor" Value="Hand"/>
	....
    </Style>
</ListBox.ItemContainerStyle>

This may not have been obvious to you, but the Cursor property here, actually refers to the ListBoxItem, so when we do this is code we must make sure to use the ListBoxItem.Cursor Dependency property. This is the case with all Setter Properties, unless they state another fully qualified property such as TextElement.FotSize.

triggerIsMouseOver.Setters.Add(
    new Setter(ListBoxItem.CursorProperty, Cursors.Hand));
styleListBoxItem.Triggers.Add(triggerIsMouseOver);

Other than that I think Styles, are pretty easy to do in code


Creating Templates In Code

Unfortunately, Templates are slightly harder to create in code than Styles. But they are still achievable. Let's consider the following DataTemplate that I have declared in XAML to represent a simple Person object

<!-- Lets have a DataTemplate for a Person-->
<DataTemplate DataType="{x:Type local:Person}">

    <StackPanel x:Name="spOuter"  Orientation="Horizontal" Margin="10">
        <Path Name="pathSelected" Fill="Orange" Stretch="Fill" Stroke="Orange" Width="15" 
            Height="20" Data="M0,0 L 0,10 L 5,5" 
            Visibility="Hidden"/>

        <StackPanel x:Name="spInner" Orientation="Horizontal">
            <Label Content="{Binding FirstName}" Foreground="Black"/>
            <Ellipse Fill="Black" Height="5" Width="5" 
                     HorizontalAlignment="Center" 
                     VerticalAlignment="Center"/>
            <Label Content="{Binding LastName}" Foreground="Black"/>
        </StackPanel>
        
    </StackPanel>
    
    <DataTemplate.Triggers>
        <DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, 
                AncestorType={x:Type ListBoxItem}, AncestorLevel=1}, Path=IsSelected}" Value="True">
            <Setter TargetName="pathSelected" Property="Visibility" Value="Visible"  />
        </DataTrigger>
    </DataTemplate.Triggers>
    
</DataTemplate>

Where a Person object looks like the following code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WPF_Mysteries
{
    /// <summary>
    /// A simple POCO, used for Binding in Window1
    /// </summary>
    public class Person
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
}

Based on what we know about WPF/XAML and what we have just seen about Styles, you would think that there was a 1 to 1 mapping for DataTemplates as well. But there aint.


I think the best way to disect this DataTemplate is piece by piece. So let's grab a section of it at a time, and then at the end I'll show the whole code section for the code created DataTemplate, that does the same as the XAML version. Let's start with the actual creation of a DataTemplate object

DataTemplate dataTemplate = new DataTemplate(typeof(Person));

That's pretty easy right. So how about getting something in the DataTemplate. Mmm, well here is the code.

Is this what you were expecting? Probably not. So what the feck is going on here. Lets start at the end to understand the beginning. We can see there is a VisualTree being set to a strange looking object of Type FrameworkElementFactory. What the F$*k!!!

To understand this, lets use our favourite tool Reflector, and get to the bottom of this. If we start with DataTemplate

Mmmm, No VisualTree property here (even though we can see that it depends on VisualTree property), but we can see this inherits from FrameworkTemplate, so let's continue to look at that.

Where the VisualTree property, looks like this

Aha, its becoming a little clearer. So we have a VisualTree property, that we need to supply a FrameworkElementFactory to. Cool. But what are these FrameworkElementFactory things. This class is a deprecated way to programmatically create templates, which are subclasses of FrameworkTemplate such as ControlTemplate or DataTemplate. MSDN Actually states "The recommended way to programmatically create a template is to load XAML from a string or a memory stream using the Load method of the XamlReader class.". But when you have to do it in code, this is your only option

So carrying on, its really just a question of creating as many of these FrameworkElementFactory objects, that you need to represent your required DataTemplates VisualTree. In my example this would be as follows

<StackPanel x:Name="spOuter">
    <Path Name="pathSelected"/>

    <StackPanel x:Name="spInner" >
        <Label />
        <Ellipse />
        <Label />
    </StackPanel>
    
</StackPanel>

For which there is a a bunch of code behind created FrameworkElementFactory objects, and they are wired up as required with all the relevant properties/relationships set in code. Finally the top level FrameworkElementFactory is set as the DataTemplates VisualTree property. So that's how the VisualTree stuff works. But what about Triggers.

Luckily Triggers are pretty easy to do in code. Here is how

DataTrigger dataTrigger = new DataTrigger();
dataTrigger.Binding = new Binding {
    Path = new PropertyPath(ListBoxItem.IsSelectedProperty),
    RelativeSource = 
        new RelativeSource(RelativeSourceMode.FindAncestor, 
        typeof(ListBoxItem), 1)
};
dataTrigger.Value = true;
dataTrigger.Setters.Add(
    new Setter(FrameworkElement.VisibilityProperty, 
        Visibility.Visible, "pathSelected"));

dataTemplate.Triggers.Add(dataTrigger);

Putting all this together we end up with a code behind DataTemplate that looks like this

//And here is the C# code to achieve the above
DataTemplate dataTemplate = new DataTemplate(typeof(Person));

FrameworkElementFactory spOuterFactory = 
    new FrameworkElementFactory(typeof(StackPanel));
spOuterFactory.SetValue(
    StackPanel.OrientationProperty, Orientation.Horizontal);
spOuterFactory.SetValue(
    StackPanel.MarginProperty, new Thickness(10));

#region Path
FrameworkElementFactory pathSelectedFactory = 
    new FrameworkElementFactory(typeof(Path), "pathSelected");

pathSelectedFactory.SetValue(Path.FillProperty, Brushes.Orange);
pathSelectedFactory.SetValue(Path.StretchProperty, Stretch.Fill); 
pathSelectedFactory.SetValue(Path.StrokeProperty, Brushes.Orange);
pathSelectedFactory.SetValue(Path.WidthProperty, 15.0);
pathSelectedFactory.SetValue(Path.HeightProperty, 20.0);
pathSelectedFactory.SetValue(Path.VisibilityProperty, Visibility.Hidden);

PathGeometry pathGeometry = new PathGeometry();
pathGeometry.Figures = new PathFigureCollection();
PathFigure pathFigure = new PathFigure();
pathFigure.StartPoint = new Point(0, 0);
pathFigure.Segments = new PathSegmentCollection();
pathFigure.Segments.Add(new LineSegment() { Point = new Point(0, 10) });
pathFigure.Segments.Add(new LineSegment() { Point = new Point(5, 5) });
pathGeometry.Figures.Add(pathFigure);


pathSelectedFactory.SetValue(Path.DataProperty, pathGeometry);
spOuterFactory.AppendChild(pathSelectedFactory);
#endregion

#region Inner StackPanel
FrameworkElementFactory spInnerFactory = new FrameworkElementFactory(typeof(StackPanel));
spInnerFactory.SetValue(StackPanel.OrientationProperty, Orientation.Horizontal);

//FirstName
FrameworkElementFactory labelFNFactory = new FrameworkElementFactory(typeof(Label));
Binding bindingFirstName = new Binding();
bindingFirstName.Path = new PropertyPath("FirstName");
labelFNFactory.SetBinding(Label.ContentProperty, bindingFirstName);
labelFNFactory.SetValue(Label.ForegroundProperty, Brushes.Black);
spInnerFactory.AppendChild(labelFNFactory);


//Ellipse
FrameworkElementFactory ellipseFactory = new FrameworkElementFactory(typeof(Ellipse));
ellipseFactory.SetValue(Ellipse.FillProperty, Brushes.Black);
ellipseFactory.SetValue(Ellipse.HeightProperty, 5.0);
ellipseFactory.SetValue(Ellipse.WidthProperty, 5.0);
ellipseFactory.SetValue(Ellipse.HorizontalAlignmentProperty, HorizontalAlignment.Center);
ellipseFactory.SetValue(Ellipse.VerticalAlignmentProperty, VerticalAlignment.Center);
spInnerFactory.AppendChild(ellipseFactory);


//LastName
FrameworkElementFactory labelLNFactory = new FrameworkElementFactory(typeof(Label));
Binding bindingLastName = new Binding();
bindingLastName.Path = new PropertyPath("LastName");
labelLNFactory.SetBinding(Label.ContentProperty, bindingLastName);
labelLNFactory.SetValue(Label.ForegroundProperty, Brushes.Black);
spInnerFactory.AppendChild(labelLNFactory);

//Add to outer StackPanel
spOuterFactory.AppendChild(spInnerFactory);
#endregion

#region DataTrigger
DataTrigger dataTrigger = new DataTrigger();
dataTrigger.Binding = new Binding {
    Path = new PropertyPath(ListBoxItem.IsSelectedProperty),
    RelativeSource = 
        new RelativeSource(RelativeSourceMode.FindAncestor, 
        typeof(ListBoxItem), 1)
};
dataTrigger.Value = true;
dataTrigger.Setters.Add(
    new Setter(FrameworkElement.VisibilityProperty, 
        Visibility.Visible, "pathSelected"));

dataTemplate.Triggers.Add(dataTrigger);
#endregion

dataTemplate.VisualTree = spOuterFactory;
return dataTemplate;

When when I run the attached app, the code behind version does exactly the same as the XAML defined version

It is more code, when compared to the XAML, but needs must

That's it

That's all I wanted to say this time, I hope it helps some of you. Could I just ask, if you liked this article please vote for it.

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
RantWhat is wrong with WPF - Styles cannot be reused ?
Gil.Y
6:47 2 Mar '10  
HELP!!!

In a seperate file I have somthing like this defined:

 <Style x:Key="DeleteButtonStyle" BasedOn="{StaticResource ResourceKey=ButtonBase}" TargetType="Button">
        <Setter Property="Button.Width" Value="60" />
        <Setter Property="Button.Height" Value="40" />
 </Style>
Inside a form I getting a nasty error for reusing this style in two places like that:

<Button Height="30" HorizontalAlignment="Left" Name="btnDelete" VerticalAlignment="Top" Width="50" Style="{StaticResource ResourceKey=DeleteButtonStyle}" />
<Button Height="30" HorizontalAlignment="Left" Name="btnDelete2" VerticalAlignment="Top" Width="50" Style="{StaticResource ResourceKey=DeleteButtonStyle}" />
The error shouts at me : "Specified element is already the logical child of another element. Disconnect it first."
When i delete the 2nd line (the one that declares btnDelete2) everything works fine.

Can anyone please explain to me what am I doing wrong as the error implies that I cannot reuse styles ???
GeneralRe: What is wrong with WPF - Styles cannot be reused ?
Sacha Barber
6:56 2 Mar '10  
I think the way you are using the Styles is wrong. Try this

<Button Height="30" HorizontalAlignment="Left" Name="btnDelete" VerticalAlignment="Top" Width="50" Style="{StaticResource DeleteButtonStyle}"/>
<Button Height="30" HorizontalAlignment="Left" Name="btnDelete2" VerticalAlignment="Top" Width="50" Style="{StaticResource DeleteButtonStyle}"/>
Sacha Barber
  • Microsoft Visual C# MVP 2008/2009
  • Codeproject MVP 2008/2009
Your best friend is you.
I'm my best friend too. We share the same views, and hardly ever argue

My Blog : sachabarber.net

GeneralRe: What is wrong with WPF - Styles cannot be reused ?
Gil.Y
7:34 2 Mar '10  
failed - same error..
GeneralRe: What is wrong with WPF - Styles cannot be reused ?
Sacha Barber
20:56 2 Mar '10  
Hard to say then from only seeing this small snippet. Sorry
Sacha Barber
  • Microsoft Visual C# MVP 2008/2009
  • Codeproject MVP 2008/2009
Your best friend is you.
I'm my best friend too. We share the same views, and hardly ever argue

My Blog : sachabarber.net

GeneralRe: What is wrong with WPF - Styles cannot be reused ?
Gil.Y
14:20 3 Mar '10  
a wpf app which reproduce the error I getting:

<Window x:Class="WpfApplication5.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="400" Width="400">
    <Window.Resources>
        <ResourceDictionary>
            <Button x:Key="smallerButton" />
        </ResourceDictionary>
    </Window.Resources>
    <StackPanel>
        <Button Content="{StaticResource ResourceKey=smallerButton}" />
        <Button Content="{StaticResource ResourceKey=smallerButton}" />
    </StackPanel>
</Window>

GeneralRe: What is wrong with WPF - Styles cannot be reused ?
Sacha Barber
21:19 3 Mar '10  
Not too sure on that one, to be honest, but I am not able to try this out at the moment, have no time, under big time scale deadlines at work, if I find a minute though I will have a look.

Ok
Sacha Barber
  • Microsoft Visual C# MVP 2008/2009
  • Codeproject MVP 2008/2009
Your best friend is you.
I'm my best friend too. We share the same views, and hardly ever argue

My Blog : sachabarber.net

GeneralRe: What is wrong with WPF - Styles cannot be reused ?
Gil.Y
6:55 5 Mar '10  
It seems that the content property is special in a way..
Only one "content" in the visual tree can contain a specific key.
I don't know if it's a bug or intended - but obviously that is the reason.
Why just content suffer from that limitation while other properties do not ?
perhaps it is because any content value is reffred as an element in
the visual tree and WPF forbid two or more elements with the same key.

Sacha, bread is before hobby - I appoligize.
Please shine at work Thumbs Up
Gil.
GeneralRe: What is wrong with WPF - Styles cannot be reused ?
Sacha Barber
7:00 5 Mar '10  
Glad you got it sorted.
Sacha Barber
  • Microsoft Visual C# MVP 2008/2009
  • Codeproject MVP 2008/2009
Your best friend is you.
I'm my best friend too. We share the same views, and hardly ever argue

My Blog : sachabarber.net

GeneralHow to create a setter with a control template inside in code behind
Angshuman
4:39 17 Dec '09  
I got this code from a MSDN sample. Unable to make out how to do something similar in the code behind. Could you please provide some idea?

 <Setter Property="Template">

<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander IsExpanded="True"

BorderBrush="#FFA4B97F"

BorderThickness="0,0,0,1">



<Expander.Content>
<ItemsPresenter />
</Expander.Content>
</Expander>
</ControlTemplate>
</Setter.Value>

Question...so why the hell would you want to do this in code...
max_cn
4:54 30 Oct '09  
Hi Sacha! I want to discuss with you about this quote:
"One thing that seems to crop up over and over again, is people really don't know how to create Styles or templates in code. Obviously XAML is better suited to doing this than code, so why the hell would you want to do this in code anyway."
First of all it is not too easy for me to speak English but I'll try.

Something about me for the beginning.
I'm newbie in WPF and now I'm preparing for Microsoft 70-502 exam (MCTS: .NET Framework 3.5 - Windows Presentation Foundation). I've 15 years of programming experience (mostly with Delphi and some script languages) and I liked C# first I see it. It gives possibility to create typesafe code which is easy to debug and read. So it was interesting for me to prepare and pass Microsoft 70-536 core exam.
C# Windows Form applications is very similar to Delphi applications, but WPF looks like much more perspective, so I decide to learn last one technology. Up to "Data binding" chapter everything was fine but now I'm shocked!

It was a good idea to separate code and UI, but, IMHO, it is very bad to incapsulate business logic and UI in the XAML. Designer must doing his part of work and the same with programmer's part. Every time designer wants to change UI you need to merge his work with yours (if you made some changes at the same time too) and it is time for mistakes!
But it is not only one problem I see. Another one with debug.
There are alot of situations now when I've no compiler errors but I got low self-descriptiveness runtime error just after application beginning. I've the same situation with the code downloaded from MSDN(!!!) with hundreds lines of XAML code and no one of C#! How could I debug it?!
It could be not bad to write XAML tags when you exactly know how to do something but it is definitely nightmare to do that for the first times without good example.

Another easy situation (closer to your article theme).
I've a list of some class instances and I want to bind it with Listbox object. I want to have possibility to add/delete some data instances and to change some fields selectively. Listbox object must display all changes immediately.
First of all I've resolve this task without templates. It was not ordinary solution (I need to wrap my collection in ObservableCollection and to realize INotifyPropertyChanged interface in my data class), but when I've found example in some blog (MSDN example was with runtime error!) it became clear.
I was upset because I can't find how to add the same bindings in the C# code:
<ListBox Name="myListBox" ItemsSource="{Binding Path=List}" DisplayMemberPath="FIO" Width="200"/>
but it was not a big problem as I see now.

Next step was to implement templates. The biggest problem I have got - I can't find how to set my instance of class collection as value of ItemsSource property of ListBox object. Something like that:
<ListBox Name="myListBox" ItemsSource="{Binding Source={list}}" 
ItemTemplate="{StaticResource ListboxTemplate}" Width="200"/>
All examples I see was with StaticResource objects. But how can change such kind of objects in my C# code?! It was fun when I see MSDN example. They add all data in the wrapper-class constructor so they create instance of collection as StaticResource and give the same binding attributes:
<ListBox Width="400" Margin="10"
             ItemsSource="{Binding Source={StaticResource myTodoList}}"
             ItemTemplateSelector="{StaticResource myDataTemplateSelector}"
             HorizontalContentAlignment="Stretch" 
IsSynchronizedWithCurrentItem="True"/>

I need hours to understand - I can set ItemsSource property in the C# code:
myListBox.ItemsSource=list;
I'm loking in XAML code but it was a big surprise to find solution in C# code Shucks .

So WPF is a big disappointment for me. I think XAML is a big mistake in current form.
AnswerRe: ...so why the hell would you want to do this in code...
Sacha Barber
0:13 31 Oct '09  
Even if you wrote all of it in code you could not test it. You have to actually run the UI to test the code if you put your code in code behind ala Winforms. People handled this in Winforms by using MVC pattern. WPF goes one better and uses MVVM pattern.

Read my Cinch series of articles and you may see it.

http://cinch.codeplex.com/[^]

Sacha Barber
  • Microsoft Visual C# MVP 2008/2009
  • Codeproject MVP 2008/2009
Your best friend is you.
I'm my best friend too. We share the same views, and hardly ever argue

My Blog : sachabarber.net

GeneralRe: ...so why the hell would you want to do this in code...
max_cn
1:26 31 Oct '09  
Sacha Barber wrote:
Even if you wrote all of it in code you could not test it. You have to actually run the UI to test the code

At least I'll got correct line of code with runtime error instead of spurious message:
"Cannot create instance of 'Window1' defined in assembly 'Practice, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. Exception has been thrown by the target of an invocation. Error in markup file 'Window1.xaml' Line 1 Position 9."
In the Winforms application when I forget to add get accessor for FIO property i've got message:
"Cannot bind to the new display member. Parameter name: newDisplayMember"
in line:
myListBox.ValueMember="FIO";
IMHO, it is much more informative. Even more, it could be better to have possibility to set such kind of values not as string but as real field with IntelliSense support... But it is only dreams.

Shame on Microsoft - I'm reading official Microsoft manual and must to search over blogs and coder communities for answers on easy questions Shucks .

Ok, thanks for information about MVVM pattern - I'm going to read about it.
Will see you later Wink .
GeneralRe: ...so why the hell would you want to do this in code...
Sacha Barber
2:06 31 Oct '09  
Its all about the tooling support my friend, XAML is easy to churn out, WinForms code is less easy for 3rd party product parsing.

I love XAML and I think if you give it a go so will you. There are ways to get rid of magic string, and binding can be validated with extremely good tracing using the approaches Bea Costa points out. These spew out more than even working with C# code behind.

http://beacosta.com/blog/?p=52[^]

Sacha Barber
  • Microsoft Visual C# MVP 2008/2009
  • Codeproject MVP 2008/2009
Your best friend is you.
I'm my best friend too. We share the same views, and hardly ever argue

My Blog : sachabarber.net

GeneralRe: ...so why the hell would you want to do this in code...
max_cn
3:17 31 Oct '09  
I'm not saying WinForms better than WPF with XAML. I'm speaking about screaming troubles with standart toolkit and about quality of the Microsoft official tutorials.
My main problem - I don't know where to look for all my questions in one place. I want to pass this Microsoft test but I want to became a real professional - not only guy with Microsoft certificate.

Thanks for link to Bea Stollnitz blog. Could you help me with good modern WPF tutorial?
GeneralRe: ...so why the hell would you want to do this in code...
Sacha Barber
3:58 31 Oct '09  
Hell man, reads loads of blogs and exploring end quantities of documentation is what makes you a "Real Professional"...If it was easy the world would be literally overrun by college kids who read MSDN, I am glad the information is hard to find, as it makes me learn it better.

My 2 cents.

Josh/Karl and Marlon have great examples as do I (sorry for the lack of modesty). I read all their stuff and we all learned off each other.

Sacha Barber
  • Microsoft Visual C# MVP 2008/2009
  • Codeproject MVP 2008/2009
Your best friend is you.
I'm my best friend too. We share the same views, and hardly ever argue

My Blog : sachabarber.net

GeneralRe: ...so why the hell would you want to do this in code...
max_cn
4:34 31 Oct '09  
Sacha Barber wrote:
Hell man, reads loads of blogs and exploring end quantities of documentation is what makes you a "Real Professional"
It was an answer of the Real Professional, thanks Smile .

Ok, I'll check all your links.
Bye for now!
GeneralRe: ...so why the hell would you want to do this in code...
Sacha Barber
5:14 31 Oct '09  
Do you know what I mean though, I never got any knowledge for free, I had to learn it all the hard way.
But it makes you better in the end.

Sacha Barber
  • Microsoft Visual C# MVP 2008/2009
  • Codeproject MVP 2008/2009
Your best friend is you.
I'm my best friend too. We share the same views, and hardly ever argue

My Blog : sachabarber.net

GeneralRe: ...so why the hell would you want to do this in code...
max_cn
7:41 31 Oct '09  
All my knowledges I've got for free Smile and I'm glad to send this knowledges to anybody who want to receive it for free too. But it's our own business, everything is ok.

Any way, thanks for links.
GeneralRe: ...so why the hell would you want to do this in code...
Sacha Barber
9:01 31 Oct '09  
No you did not get it for free, you had to work for it that's my point. Knowledge should be hard to obtain, thats the whole point of it.

Sacha Barber
  • Microsoft Visual C# MVP 2008/2009
  • Codeproject MVP 2008/2009
Your best friend is you.
I'm my best friend too. We share the same views, and hardly ever argue

My Blog : sachabarber.net

GeneralRe: ...so why the hell would you want to do this in code...
max_cn
10:26 31 Oct '09  
Why we still speaking about knowledges Wink ?

I've only one question: why are you writing all that articles here?
I've write my first one because I hope it can be interesting for somebody who are looking for original solution. It is impossible to obtain something without intellectual work. And I'm glad to find intresting solutions and ideas. To think about it and understand how it's realy easy and genial at the same time...
I hate people who ask you to do all them job but I'm open for anybody who are loking for knowledges because in any case it is a hard job to obtain any kind of attainments, IMHO.
GeneralRe: ...so why the hell would you want to do this in code... [modified]
max_cn
12:56 31 Oct '09  
I've think about our conversation and see - it is possible you don't understand me correctly because of my bad English Blush .
When I speak about tutorials I mean: do you know some good modern WPF book or something like that for somebody who are newbie now but wants to grow up on good ideas and examples?

modified on Monday, November 2, 2009 7:03 AM

GeneralRe: ...so why the hell would you want to do this in code...
max_cn
2:16 2 Nov '09  
Sacha Barber wrote:
WPF goes one better and uses MVVM pattern.
I'm reading now walkthrough for MVVM Toolkit and it's looks like you was right.
Using this pattern is a good improvement for WPF. I'll read your Cinch series of articles when I finish with first toolkit.

Thanks for link to really useful idea.
QuestionLimitation
Member 4756549
4:04 6 Oct '08  
Is it possible to create in code a DataTemplate with a ContextMenu? I always get an exception.
AnswerRe: Limitation
Sacha Barber
10:24 6 Oct '08  
It should be possible. Everything that can be done in XAML can be done in code, so try the XAML 1st.

Sacha Barber
  • Microsoft Visual C# MVP 2008
  • Codeproject MVP 2008
Your best friend is you.
I'm my best friend too. We share the same views, and hardly ever argue

My Blog : sachabarber.net

AnswerRe: Limitation
Member 4756549
22:43 6 Oct '08  
In XAML it works, used many times, but not in code.

FrameworkElementFactory textBoxF = new FrameworkElementFactory(typeof(TextBox));
FrameworkElementFactory contextMenuF = new FrameworkElementFactory(typeof(ContextMenu));
FrameworkElementFactory menuItemF = new FrameworkElementFactory(typeof(MenuItem));
menuItemF.SetValue(HeaderedItemsControl.HeaderProperty, "hallo");
contextMenuF.AppendChild(menuItemF);
textBoxF.SetValue(FrameworkElement.ContextMenuProperty, contextMenuF); // exception not a valid value

I always get a lot of inspiration from your articles, thanks for them!


Last Updated 26 Sep 2008 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010