Monika Dyrda

WPF Dev Girl
Hello Caliburn – beginners guide to an amazing framework (1)

I knew about Caliburn for some time but never really tried it until I've found a very simple solution to a problem that appeared complicated. After struggling a bit and asking some newbie-stupid questions on twitter I've decided to get to know the framework from the beginning. And of course I was trying to understand a big sample before reading any documentation so everything seemed very hard and complicated. Since I could not find any tutorial with a legendary 'hello caliburn' application I've decided to write one - for me to remember basics and maybe for someone else to get them too.

Caliburn gives a WPF developer a lot of helpers but for me the most important was to make me use presentation patterns properly, make my code neat, well organized, easy to read. I also hope to learn some about testability goods that comes with using Caliburn. This post is based on an application given as a sample with the release and shows how to build a very first Cliburn application.

CaliburnApplication

To make things easiest possible I've decided not to try manual configuration and use a CaliburnApplication class. It configured everything I needed. Now my application is:

using Caliburn.PresentationFramework.ApplicationModel;
namespace HelloCaliburn
{
public partial class App : CaliburnApplication{}
}
<ApplicationModel:CaliburnApplication x:Class="HelloCaliburn.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ApplicationModel="clr-namespace:
Caliburn.PresentationFramework.ApplicationModel;
assembly=Caliburn.PresentationFramework"
>
</ApplicationModel:CaliburnApplication>

View

<Window x:Class="HelloCaliburn.Views.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Hello" Height="300" Width="300">
<Label Margin="50" Content="Hello Caliburn! :-)"/>
</Window>

Presenter

namespace HelloCaliburn.Presenters
{
public class MainPresenter : IMainPresenter {}
public interface IMainPresenter {}
}

The only important thing to remember is naming conventions. Views should be named: My.Namespace.Views.NameView and presenters My.Namespace.Presenters.NamePresenter
It helps to have the same folders names (another benefit of Caliburn - I've learned that naming and putting things in common places is good and important)

image

Final application

One small method in the application class:

public partial class App : CaliburnApplication
{
protected override object CreateRootModel()
{
return Container.GetInstance<IMainPresenter>();
}
}
One attribute to register my presenter:
[PerRequest( typeof( IMainPresenter ) )]
public class MainPresenter : IMainPresenter
{
}
Hit F5 and done :-)
image 
Happy caliburning ;-) Code here,
Monika
 
Posted: Oct 26 2009, 09:46 PM by xmonix | with 1 comment(s)
Filed under: ,
WPF: ListCollectionView for sorting, filtering and grouping

I have written before that I need and like WPF lists (ListBox, ListView..) very much. Now I'd like to share a method to manipulate the view when being simply bound to a collection without touching this collection. It can be done in xaml as shown here but I don't like this approach very much because in my opinion operations like sorting, grouping belong to view model not directly view and no tests will be available if they are in view.

Example

So the sample problem is we have a view with a ListBox which ItemsSource is bound to an ObservableCollection. In my example I have a list of True Blood characters. Each creature has first name, last name, age (made up) and kind (it can be either vampire, human or mystery). A model of creature is (very simple just to have some data):

public class CreatureModel
{
public CreatureModel( string firstName, string lastName, int age,
CreatureKind kind )
{
this.FirstName = firstName;
this.LastName = lastName;
this.Age = age;
this.Kind = kind;
}

public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public CreatureKind Kind { get; set; }

public override string ToString()
{
return string.Format( "{0} {1} {2} {3}", this.FirstName,
this.LastName, this.Age, this.Kind );
}
}


View is contains a ListBox and three buttons:

<ListBox ItemsSource="{Binding Path=CreaturesCollection}" />
<Button Content="Sort by age"
Command="{Binding Path=SortByAgeCommand}"/>
<Button Content="Filter Vampires"
Command="{Binding Path=FilterVampiresCommand}"/>
<Button Content="Group by kind"
Command="{Binding Path=GroupByKindCommand}"/>

View model for this problem is also simple – we need a collection of creatures and commands for sorting, filtering and grouping:

public ObservableCollection<CreatureModel> CreaturesCollection 
{ get; private set; }
public ICommand SortByAgeCommand
{ get { return new DelegateCommand(this.SortByAge ); } }
public ICommand FilterVampiresCommand
{ get { return new DelegateCommand( this.FilterVampires ); } }
public ICommand GroupByKindCommand
{ get { return new DelegateCommand(this.GroupByKind ); } }

And now all the magic needed to implement three methods – parameters in DelegateCommand constructor is this method:

private ListCollectionView GetListCollectionView()
{
return (ListCollectionView) CollectionViewSource
.GetDefaultView( this.CreaturesCollection );
}

CollectionViewSource


CollectionViewSource  – when you set a binding to a collection, WPF makes it a binding to the default view for that collection. CollectionViewSource has a static method that lets getting this default view: CollectionViewSource.GetDefaultView and on the view filtering, grouping, sorting can be easily applied ListCollectionView is a default view for collections implementing IList.

Sorting – ListCollectionView.CustomSort

To apply sorting an implementation of IComperer is needed and it can be any implementation of this interface. I will use one that simply sorts creatures by age:

public class SortCreaturesByAge : IComparer
{
public int Compare( object x, object y )
{
if( x as CreatureModel == null && y as CreatureModel == null )
{
throw new ArgumentException( "SortCreatures can
only sort CreatureModel objects."
);
}
if( ((CreatureModel) x).Age > ((CreatureModel) y).Age )
{
return 1;
}
return -1;
}
}


Now I can implement a method used for SortByAgeCommand by setting CustomSort on ListCollectionView:

public ICommand SortByAgeCommand 
{ get { return new DelegateCommand(this.SortByAge ); } }
private void SortByAge()
{
this.GetListCollectionView().CustomSort = new SortCreaturesByAge();
}


Unsorted and sorted collection:


image image

Filtering – ListCollectionView. Filter

I would like to implement a filter which shows only vampires from the list of creatures. Filter is a Predicate<bool>. Even simpler than in sorting, we just need
a method that returns a bool deciding whether a parameter object is what we need:

private bool IsAVampire( object obj )
{
if(obj as CreatureModel != null
&& (obj as CreatureModel).Kind == CreatureKind.Vampire)
{
return true;
}
return false;
}


Clicking on “Filter vampires” shows only vampires :-)

image

Grouping

I would like to group all creatures on my list by kind. Kind is an enum:

public enum CreatureKind
{
Human,
Vampire,
Mystery
}


Again ListCollectionView comes with a solution. All needed to be done is adding a property name that grouping will be based on. I this exaple – kind:

public ICommand GroupByKindCommand 
{ get { return new DelegateCommand(this.GroupByKind ); } }
private void GroupByKind()
{
this.GetListCollectionView().GroupDescriptions.Add(
new PropertyGroupDescription { PropertyName = "Kind" } );
}


Now list can be grouped:

image

Sum up

Grouping, filtering and sorting are supported by WPF very well and are easy to apply. I feel that my example is very basic and like always in WPF lots of customising can be done here. Next thing I plan to discover is a neat and smart way of setting data templates and styles for this kind of problems.

Code here. As always any suggestions very welcome.


Monika

Posted: Aug 31 2009, 08:00 PM by xmonix | with 5 comment(s)
Filed under:
Seadragon is so cool! ;-)

 I know this post may be useless for most people but I've been looking at seadragon and found it so cool I can't resist... :-)

 

WPF TextBox validation 2

Many people asked me how to enable/disable button depending on a few TextBoxes. I would strongly recommend Caliburn but I know not everyone can use it. So I’ve decided to post a very simple solution to that problem.

First of all we need a ViewModel and I will use a very simple class which has IsValid method – checking if data is valid, ICommand property to be bound to a Button and an action to be executed when the button is pressed.

    class PersonViewModel
{
public string Name { get; set; }
public int Age { get; set; }

public bool IsValid()
{
if(string.IsNullOrEmpty(this.Name))
{
return false;
}
if(this.Age < 5 || this.Age > 120)
{
return false;
}
return true;
}

public ICommand OkCommand
{
get { return new DelegatedCommand(this.OkAction, this.IsValid); }
}

private void OkAction()
{
MessageBox.Show("ok!");
}
}

TextBox.Text properties can now be bound to properties of this class and button’s command can be bound to OkCommand. Automatically button will be enable when command can be executed and disabled when command cannot be executed:

<TextBox Text="{Binding Path=Name}"/>
<TextBox Text="{Binding Path=Age}"/>
<Button Command="{Binding Path=OkCommand}" Content="ok"/>

My ICommand implementation in this example is very naive. Maybe a better one in a next post? :-)

Results disabled and enabled:

image image

Code here

Monika

Posted: Jul 28 2009, 07:13 PM by xmonix | with 1 comment(s)
Filed under:
WPF ToolTip Content binding

Did you know that content of a ToolTip is neither a part of visual nor logical tree? I didn't so I was trying to bind a ToolTip.Content using ElementName. And it didn't work:

<TextBlock Name="box" Text="Text to place inside tooltip" />
<Button Content="Can't Bind">
<Button.ToolTip>
<ToolTip Content="{Binding ElementName=box,
Path=Text}"
/>
</Button.ToolTip>
</Button>

Button has a tiny empty tooltip:

EmptyTooltip

This code seemed perfectly fine for me so it took me a lot of time to google the answer. The only way to make that binding happen doesn't look nice but it's a simple trick: bind to a Grid DataContext. Seriously :-)

<Grid DataContext="{Binding ElementName=box, Path=Text}" >
<Button Content="Tricky Evil Solution ;-)"/>
<Grid.ToolTip>
<ToolTip Content="{Binding Path=PlacementTarget.DataContext,
RelativeSource={RelativeSource Self}}"
/>
</Grid.ToolTip>
</Grid>

And now the tooltip looks ok:

WorkingTooltip

My original problem was binding a ToolTip.Content to validation errors and I really needed a way to do that. Please tell me if you know a better one :-)
Code can be found here.

Monika

Update: This works too! :-)

<Button ToolTip="{Binding ElementName=box, Path=Text}"  />
WPF TextBox Validation

Sample problem: set parameter by entering value into a TextBox, check if value is a number in given range, allow clicking a Button if validation was successful.

ValidationRule

ValidationRule is an abstract class from System.Windows.Controls that helps creating custom validation rules for user input.  In this example a derived class DoubleRangeRule will check if user entered a number (double) within a given range (between Max and Min value).

public class DoubleRangeRule : ValidationRule
{
public double Min { get; set; }

public double Max { get; set; }

public override ValidationResult Validate( object value,
CultureInfo cultureInfo )
{
double parameter = 0;

try
{
if( ((string) value).Length > 0 )
{
parameter = Double.Parse( (String) value );
}
}
catch( Exception e )
{
return new ValidationResult( false, "Illegal characters or "
+ e.Message );
}

if( (parameter < this.Min) || (parameter > this.Max) )
{
return new ValidationResult( false,
"Please enter value in the range: "
+ this.Min + " - " + this.Max + "." );
}
return new ValidationResult( true, null );
}
}

 

Validation.ErrorTemplate

Having defined ValidationRule as above if user input is invalid, TextBox will have a red border. Like everything in WPF it is possible to customize it by setting a custom ControlTemplate. My template shows a warning sign and a label explaining error made by user (why input is invalid):

<ControlTemplate x:Key="TextBoxErrorTemplate">
<StackPanel>
<StackPanel Orientation="Horizontal">
<Image Height="16" Margin="0,0,5,0"
Source="Assets/warning_48.png"/>
<AdornedElementPlaceholder x:Name="Holder"/>
</StackPanel>
<Label Foreground="Red" Content="{Binding ElementName=Holder,
Path=AdornedElement.(Validation.Errors)[0].ErrorContent}"
/>
</StackPanel>
</ControlTemplate>

Read more about AdornedElement here.

Binding to validation result

On the result of validation can depend many things. For example I would like to bind button IsEnabled property to that deciding to enable button only in user input is valid. Simplest way, in my opinion is to check if TextBox has any validation errors and if no – make button enabled, disabled otherwise. With TextBox called Box (x:Name) binding of Button's IsEnabled property looks like that:

IsEnabled="{Binding ElementName=Box, Path=(Validation.Errors)[0], 
Converter={StaticResource buttonEnabled}}"

 

Final app


Finally we get a TexBbox with validation rules, tips on incorrect input and a Button bound to correctness of input.

<TextBox x:Name="Box" 
Validation.ErrorTemplate="{StaticResource TextBoxErrorTemplate}">
<TextBox.Text>
<Binding Path="ValueInBox" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<ValidationExpamples:DoubleRangeRule Min="0.5" Max="10"/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
<Button Content="SaveChanges"
IsEnabled="{Binding ElementName=Box, Path=(Validation.Errors)[0],
Converter={StaticResource buttonEnabled}}"
/>

CorrectValue IncorrectValue

 

If anyone had an idea how to do things like that a better way comments would be much appreciated. VS2008 project here.

Monika

DeepZoomPix and my trip to Paris

 DeepZoomPix is just amazing! Easy to use with great way of showing the world your photos. And it's Silverlight and Azure... :-)

Posted: Apr 16 2009, 04:59 PM by xmonix | with no comments
Filed under:
Master-Detail patter implemented using WPF

The master-detail pattern is a very neat way of displaying and organizing data that falls within some hierarchy. It is a quite efficient way of creating a custom user experience by allowing the user to start from various entry points and navigate to the items they are interested in. Master-detail pattern is used in almost all desktop and web applications so recently I also came across a problem that needed its implementation. If you've never done that and you like data binding as much as I do keep reading to see how it can be done in WPF :-)

Problem definition: I have a list of animal species and a list of examples for each of the species. Every example have some additional information. I would like to organize it nicely into two lists (species, examples) and a custom way of displaying the additional information. User will choose a species and see a list of examples, than he will choose an example an see the details.

Master-detail solution: (1) the list of species is a master for the examples list, the examples list is a detail for each item in the list of species (2) the examples list is a master for additional information, additional information is a detail for each item in the list of examples. So my solution will use master-detail patter twice.

Implementation details: LifeSource is an object of a data source containing all data I need to create this example. First of all I bind a collection of Spiecies to items source of a ListBox:

<ListBoxName="SpeciesListBox" 
ItemsSource="{Binding Path=LifeSource.SpeciesCollection}"/>

Than another list box items source is bound to a selected element from the first one (species – examples):

<ListBox Name="AnimalsListBox" ItemsSource="{Binding 
Path=SelectedItem.Animals, ElementName=SpeciesListBox}"
/>

And last binding – some controls which will show the additional information about items from AnimalsListBox:

<Label Content="{Binding Path=SelectedItem.Name, 
Mode=OneWay, ElementName=AnimalsListBox}"
/>
<Label Content="{Binding Path=SelectedItem.LatinName,
Mode=OneWay, ElementName=AnimalsListBox}"
/>
<Image Source="{Binding Path=SelectedItem.Photo,
Mode=OneWay, ElementName=AnimalsListBox}"
/>

Finally the master-detail animal show (selected items have blue background):

MasterDetailScreen

Here you can find c#/xaml code and VS2008 project. All photos and information used in this example comes from Wikipedia.

Posted: Mar 13 2009, 04:49 PM by xmonix | with no comments
Filed under:
UX Design Patterns

Quince is a small Asian tree with pinkish flowers and pear-shaped fruit (as described here). But there is another thing called Quince. It’s a great source of knowledge about UX patterns.

I have found it very interesting and useful. Personal favorite: Hub and Spoke. Moreover in my opinion Quince itself is a very good example of well designed UI with amazing UX. So this evening I will dig in and hope to learn a lot :-)

Monika

Posted: Feb 03 2009, 05:54 PM by xmonix | with no comments
Filed under:
WPF Binding ItemsSource to Enum

I have found a very neat and simple way of binding an ItemControl to enum values. The trick is to use an ObjectDataProvider class which enables the creation of a XAML object available as a binding source.


To show an example first of all I need an enum:

public enum SampleEnum
{
Dog,
Cat,
Scrat,
Hefalump
}

To make it available for binding I will define it as a resource with an x:Key.

<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:System="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:WpfApplication1"
Title="Bind to Enum" Height="250" Width="250">
<Window.Resources>
<ObjectDataProvider x:Key="dataFromEnum"
MethodName="GetValues" ObjectType="{x:Type System:Enum}">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="local:SampleEnum"/>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</Window.Resources>
</Window>

This code creates the ObjectDataProvider in the window with ObjectType property set to Enum and MethodName property set to GetValues method of the Enum class. Then a specific enum (SampleEnum) is set to MethodParameter attribute.

Having this resource we can bind it as an ItemsSource to a ListView and Combobox (or any other ItemsControl) by setting items source:

ItemsSource="{Binding Source={StaticResource dataFromEnum}}"

The XAML for the window is as follows:

<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:System="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:WpfApplication1"
Title="Bind to Enum" Height="250" Width="250">
<Window.Resources>
<ObjectDataProvider x:Key="dataFromEnum"
MethodName="GetValues" ObjectType="{x:Type System:Enum}">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="local:SampleEnum"/>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</Window.Resources>
<Grid>
<ListView ItemsSource="{Binding Source={StaticResource dataFromEnum}}"
Margin="10,10,10,0" Height="80" VerticalAlignment="Top" />
<ComboBox ItemsSource="{Binding Source={StaticResource dataFromEnum}}"
Margin="10,0,10,80" Height="25" VerticalAlignment="Bottom" />
</Grid>
</Window>

The code behind for window is:

using System.Windows;
namespace WpfApplication1
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
}
public enum SampleEnum
{
Dog,
Cat,
Scrat,
Hefalump
}
}

And the result:

BindToEnum 

Happy Binding! ;-)

Monika

Posted: Jan 08 2009, 08:39 PM by xmonix | with no comments
Filed under:
More Posts Next page »