This blog has moved
Thanks for stumbling upon my blog…
I’ve moved my ramblings and ill-informed opinions to http://xaml.geek.nz
thanks, Ian
Something strange…
I saw something strange today, so I tried to isolate and reproduce the problem, and I think I have.
This is what I was trying to do:
- I’m writing a gate entry application for a gym. When a member swipes their badge, a popup appears in the bottom-right corner.
- The popup is green (if it’s a valid swipe) or red if not.
- Additionally, the popup may show any number of alerts (e.g. overdue fees, barcode not found, Happy Birthday!, etc…)
So to implement this, I figured I’d create a Window, place it in the bottom-right corner of the screen; create an EntryViewModel (perform rules and logic to work out the state of the ‘Entry’) and finally, use a TemplateSelector to decide how to present the Popup view…
One thing I wanted to do was slide the red ones over to the left side of the screen, and keep them there (the green ones automatically fade away after 2 or 3 seconds)
So I added an animation in the UserControl to grab the parent Window (using a FindAncestor RelativeSource) and decrease the ‘Left’ property down to 0 over 1/2 a second.
What I saw was only *one* of the animations worked… that is, if the window contained a ‘green’ user control, it would fade away, but if it was for a ‘red’ one, it wouldn’t slide off to the left…
Puzzled, I changed the green animation to slide (instead of fade), and still it worked, but still the red one didn’t…
Well this bothered me, so I added a TextBlock into the UserControl, setting the Text to the exact same Binding as the animation (to make sure the parent Window was being correctly derived), and guess what? The animation started working…
Huh? I figured something had gone a bit wrong, and changing the template and re-compiling had fixed it, so I commented out the TextBlock and tried again… bugger me if the animation didn’t stop working again…
I’ve attached a sample app that demonstrates the problem… If anyone can unravel this and let me know what I’ve done wrong, I would be much obliged.
In the meantime, I have a TextBlock in my UserControl with Visibility set to ‘Hidden’ and a bloody big comment next to it saying ‘do not remove this seemingly meaningless TextBlock – It makes the animation work!!’
Update:
WPF Disciple, Microsoft MVP and thoroughly bloody good bloke Paul Stovell enlightened me on this one… What was happening was, the UserControls were attempting to run an animation whose Target objects were the parent Window for the Control. To find the Window, I had ‘reached up and out of the Control’, like this:
<DoubleAnimationUsingKeyFrames
Storyboard.Target="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"
Storyboard.TargetProperty="Left">
<LinearDoubleKeyFrame KeyTime="0:0:2" Value="50.0" />
</DoubleAnimationUsingKeyFrames>
but the problem was that this animation was being run (and hence this Binding was being evaluated) before the UserControl had been added to the Visual tree, due the way the Loaded event fires…
The ‘green’ UserControl contained a TextBlock that binds to the name off the EventViewModel, and subsequently the UserControl loaded event is fired just that little bit later (after the Control is added to the Visual tree) – so the ‘green’ ones were working just fine…
As per his suggestion, I have created the animations directly in the parent window (thereby removing the FindAncestor Binding), and fired an event in the UserControl to let the parent know some animation needs to be run…
I’l leave the problematic code here for reference: To see the problem, comment out the TextBlock from any of the UserControls…
Download:
Implementing validation in your ViewModels
It’s easy to implement validation in WPF. If your ViewModel implements IDataErrorInfo interface from the System.ComponentModel namespace, then WPF will take care of all the heavy-lifting for you… you’ll probably find your VM looking something like this:
#region IDataErrorInfo Members
public string Error { get; private set; }
public string this[string columnName]
{
get
{
Error = null;
switch (columnName)
{
case "Name":
if (string.IsNullOrEmpty(Name))
Error = "Name cannot be blank";
break;
case "Age":
if (Age < 0)
Error = "Age cannot be less than zero";
break;
}
return Error;
}
}
#endregion
Now, to get this validation to appear in the View, we just need to add an attribute to our property binding, like this:
<TextBox Text="{Binding Path=Name, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" />
Now if the field fails validation, WPF will (by default) draw a red box around the invalid field, so it will look like this:
So this is all lovely, but if you have dozens and dozens of ViewModels that each contain dozens of properties that need validating, then wouldn’t it be much nicer to simplify the process? Well, the good news is that we can…
Firstly, we will create an abstract base class for our ViewModels, and make this class implement IDataErrorInfo. Now we will use custom attributes to perform the actual property validation, so we can decorate the VM properties in a single line…
We’ll probably have a collection of common validation rules, for which we will create a custom attribute, so we’ll create a ValidationAttribute base class, like this:
[AttributeUsage(AttributeTargets.Property, AllowMultiple=true)]
protected abstract class ValidPropertyAttribute : Attribute
{
protected string _errorMessage;
public ValidPropertyAttribute(string errorMessage)
{
_errorMessage = errorMessage;
}
public abstract string ValidateProperty<T>(T value);
}
Just a couple of things to note here:
- We have constrained our attributes to only apply to Properties on the ViewModel class – Visual Studio will alert us at design-time if we attempt to decorate a method or a field.
- We have allowed for multiple attributes to be applied to a single property.
- The base constructor takes a string parameter to hold the ‘error message’ – this is what will be passed back to the user if validation fails
- We have included an abstract generic method ValidateProperty – this is where the calling code will pass in the property value to be validated. This will need to be implemented on all concrete Attributes that inherit this base class.
A most common validation would be that a string property cannot be blank… our custom attribute for this validation will look like this:
protected class PropertyCannotBeEmptyStringAttribute : ValidPropertyAttribute
{
public PropertyCannotBeEmptyStringAttribute(string errorMessage)
: base(errorMessage) { }
public override string ValidateProperty<T>(T value)
{
string stringValue = value as string;
if (string.IsNullOrEmpty(stringValue))
return _errorMessage;
return null;
}
}
So the ValidateProperty method simply passes in the parameter, this gets cast as a string, and if the string is null or empty, we return the _errorMessage stored in the base class. Nice, eh?
Finally, to wire all this up, we need to join the dots between the IDataErrorInfo interface and our custom attributes. To do this, we need to put the following code in the ViewModelBase:
public string Error { get; private set; }
public string this[string columnName]
{
get { return Validate(columnName); }
}
protected string Validate(string propertyName)
{
var property = GetType().GetProperty(propertyName);
if (property == null)
throw new ArgumentException("propertyName must indicate a valid property on the object");
Error = null;
foreach (ValidPropertyAttribute attribute in property.GetCustomAttributes(typeof(ValidPropertyAttribute), true))
{
var err = attribute.ValidateProperty(property.GetValue(this, null));
if (err == null) continue;
if (Error == null) Error = err;
else Error += string.Format("{\r\n{0}", err);
}
return Error;
}
Now it’s all wired up, we can simply decorate the ViewModel’s property like this:
[PropertyCannotBeEmptyString("Please specify a name")]
public string Name
{
get { return _name; }
set
{
if (value == _name) return;
_name = value;
RaisePropertyChanged(() => Name);
}
}
Source code: Rename file extension from .doc to .zip
ValidationSample.doc
Gorgeously simple – part 3
To wrap up this brief series of demonstrations, I’m just going to glue the previous two posts together to show you something that made me go ‘wow’
We’ve looked at how to display an object, and how to display a list of objects on a window using a DataTemplate and some simple DataBinding.
Put these two concepts together, mix it up with WPF’s ‘Current Item’ functionality and what have you got? A super-simple Master-Detail page…
1. Using the DataTemplates defined in the previous posts, split the Window’s main grid into two; put the list on the left hand side, then the detail in the right
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ListBox
Grid.Column="0"
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding}" ItemTemplate="{StaticResource bookListItemTemplate}"
HorizontalContentAlignment="Stretch" />
<ContentPresenter
Grid.Column="1" Margin="4"
Content="{Binding}" ContentTemplate="{StaticResource bookTemplate}" />
</Grid>
2. Remark upon how Robert is your Father’s Brother… It truly is that easy.
So how do you refresh the ContentPresenter with the data from the selected item from the list on the left-hand side? You absolutely don’t need to… Synchronising the ‘current item’ with the ListBox does all the work for you… cool eh?
One last thing: Notice how we’ve bound the ItemsSource to the DataContext of the ListBox (and, by extension since the DataContext is not explicitly set, the DataContext of the Window)? This is (from the previous post) a list of books, which appears in the list box exactly as one would expect.
Now notice how we have bound the Content of the ContentPresenter to exactly the same object (i.e. a list of books)? The ContentPresenter is smart enough to work out that it can only cope with one thing at a time, so it simply takes the current item out of the list and presents that…
Master-detail pages have never been so simple…
Gorgeously simple – part 2
Remember how easy it is to display ‘something’ in WPF? Well, what if you’ve got a whole list of stuff? no probs…
1. Create a real simple DataTemplate, similar to last time…
<DataTemplate DataType="{x:Type local:Book}" x:Key="bookListItemTemplate">
<DockPanel>
<TextBlock DockPanel.Dock="Right" Width="60" Text="{Binding StringFormat={}{0:yyyy}, Path=FirstPublished}" />
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0}, {1}">
<Binding Path="Title" />
<Binding Path="Author" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</DockPanel>
</DataTemplate>
2. Set the DataContext to be a list of our stuff… anything that implements the IList interface will do… List<T> is the easiest for demonstration purposes (more on this later)
IList Books = new List<Book>
{
new Book
{
Author = "Orson Scott Card",
Title = "Ender's Game",
FirstPublished = new DateTime(1977, 08, 01),
Publisher = "Tor books"
},
new Book
{
Author = "Terry Pratchett",
Title = "Mort",
FirstPublished = new DateTime(1987, 01, 01),
Publisher = "Victor Gollancz"
},
new Book
{
Author = "Truman Capote",
Title = "In Cold Blood",
FirstPublished = new DateTime(1966, 01, 01),
Publisher = "Random House"
}
};
this.DataContext = Books;
3. Throw the list onto the View in an items presenter…
<ListBox
ItemsSource="{Binding}" ItemTemplate="{StaticResource bookListItemTemplate}"
HorizontalContentAlignment="Stretch" />
Seriously, what could be simpler? Isn’t WPF stunning? notice how I have deliberately not introduced glimmering shadow effects or animations to spin the controls into place? WPF is not (only) ‘eye-candy’… the aesthetic beauty comes from the delicious simplicity with which we can generate ultra-powerful user interfaces, in order to deliver pleasurable user-experiences…
I just love it
Gorgeously simple – part 1
Adding a ‘thing’ to a View in WPF is deliciously simple…
Step 1.
Define your thing
public class Book
{
public string Title { get; set; }
public string Author { get; set; }
public DateTime FirstPublished { get; set; }
public string Publisher { get; set; }
}
Step 2.
Define the WPF template for presenting this thing to the world…
<DataTemplate DataType="{x:Type local:Book}" x:Key="bookTemplate">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Title" />
<TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Title}" />
<TextBlock Grid.Row="1" Grid.Column="0" Text="Author" />
<TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding Author}" />
<TextBlock Grid.Row="2" Grid.Column="0" Text="Published" />
<TextBlock Grid.Row="2" Grid.Column="1">
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} ({1:MMM yyyy})">
<Binding Path="Publisher" />
<Binding Path="FirstPublished" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</Grid>
</DataTemplate>
Step 3.
Set the DataContext of your view to be an instance of your thing…
public Window1()
{
InitializeComponent();
this.DataContext = new Book
{
Author = "Orson Scott Card",
Title = "Ender's Game",
FirstPublished = new DateTime(1977, 08, 01),
Publisher = "Tor books"
};
}
Step 4.
Just chuck your thing on the screen…
<ContentPresenter Content="{Binding}" ContentTemplate="{StaticResource bookTemplate}" />
Content="{Binding}" means just use the object set as the DataContext, and ContentTemplate="{StaticResource bookTemplate}" means use the template called ‘bookTemplate’ to render the thing…
and you see…
Salesforce Studio
I’ve been using force.com as a development platform for over a year now, and quite frankly the development experience is as bad as it’s always been. The Eclipse plug-in, whilst now being officially supported by Salesforce.com, still delivers a very poor development experience. Too many functions rely too heavily on lengthy, synchronous operations to work, namely:
- Saving code to the salesforce server
- Loading code in the editor – just double-clicking the filename in the project explorer can result in a 10 second delay whilst Eclipse heads off to San Francisco to check for code-differences… My code is synchronised with TFS (via a nice extension called Teamprise) so I don’t care if it’s in sync with the sandbox or not – I can deploy the whole code-base up to the sand box if I want!
- Intellisense – this was a recent addition to the toolkit (and it was hateful not having it) but Ctrl+Space can mean another 10-second delay whilst it sorts out its dictionary and works out what words to offer up in auto-complete. Sometimes it doesn’t offer any choices when you know there should be some… I have learnt that placing a space immediately after an opening parenthesis for a method call gives me a much greater chance of having intellisense offer anything up at all – but then I waste clicks and keystrokes tidying up the meaningless spaces, because I’m so pedantic about the aesthetics of my code…
So anyway, my plans to write an IDE continue apace – nothing in the Eclipse/supporting offerings world has diverted me from this task.
What *has* diverted me from this task, however, is the small matter of a brand shiny new IDE called Visual Studio 2010 and the release of .net 4.0 beta. Like a magpie I have chased the shiny new stuff without a moment’s thought for the tatty old rubbish left behind… this is why in the real world, developers need project managers, but hey – this isn’t the real world, it’s my pet project, so I get to make these calls
So the scope of the assignment hasn’t really changed – I still want a text editor that is lean and responsive – I’m only trying to write text to my c: drive for goodness sake – one that can take a process that is potentially lengthy, like deploying code to a web service, and run them asynchronously to ensure the application retains that responsiveness.
But the subtle difference in the technology stack is that I’m targeting .net 4.0 (not 3.5), and I’ve also found a couple of really nice open-source projects that will help me no end.
AvalonDock is a window-docking solution, that offers drag-and-drop, window splitting and more with a clean API; AvalonEdit is part of SharpDevelop, a full open-source IDE that has about a gazillion features and attempts to be an open-source Visual Studio replacement… I just need the text editor, thank you
I’ve also signed in blood to get the binaries for the WPFRibbon – Microsoft are just sorting their shit out between the Office team and the developer teams.. I’m reasonably sure the Ribbon will become a standard control, baked into Studio at some stage in the future, so I think I can screen-shot the work I’ve done with it, but if not, they can always repossess my house or whatever…
So here’s a sneak-peak at a vanilla, style-less version of the product so far…
Trying to do things properly
I’m trying to write a *proper* WPF application, and as my understanding of MVVM matures, I no longer consider it an MVVM application; rather an amalgam of MVC and MVVM…
I’ve taken, as I previously posted, Josh Smith’s MvvmFoundation library from Codeplex, and sat it behind a WPF app that is structured remarkably like his MVVM Demo… so far, so groovy, but the more I journey down this rocky path of learning, the more I see the world in the following way:
- The Model is responsible for storing data. If we need to transport that data to/from a database, we can use an ORM to get it here.
- The View is responsible for interacting with the user. It presents things on the screen, and handle user input.
- The ViewModel is responsible for taking stuff stored in the Model, applying Business Rules and other ‘state’ variables to the data and offering it up to the View.
The classic example is a flag on an object called “Status”
The Model holds “Active”, “Inactive” and “Terminated”
The View displays a circle, coloured green, orange or Red (respectively)
Rule: A customer is inactive if they have not made a purchase in 60 days, and Terminated if they have cancelled their contract, or not made a purchase in 12 months.
So a customer record is brought up by the user, and there’s a little circle in the corner of the for, but how do we decide whether to colour it in green, orange or red? One way would have been to run the business rule in the form_load event of our winForm, and now we have the classic ‘business rules in the View’ mess. The code in (and behind) the view *should* be concerned with creating a circle on a form, but it absolutely should *not* be concerned with running business rules to calculate what colour that should be… this is the core of what “Separation of concerns” is all about…
Why? Well, now we have a discreet, stand-alone piece of logic whose input is a Customer “last purchased date”, and whose output is a “status”. It is trivial to unit-test this, without having to load forms, or even build the whole application and run it. Woot!
So we drop the logic into a ViewModel. The ViewModel knows about the Model, and the Model stores the “last purchased date”; The rule can either be coded in, or else the parameters (number of days before inactive, and number of days before terminated) can be stored somewhere to be administered by a user; The customer status can be calculated, and the ViewModel can expose a Property called “Status”.
Now the View, which is binding to the ViewModel can access this property, and, using a ValueConverter, turn “Active” into Green, Inactive into Orange, etc…
OR: You could code the ViewModel safe in the knowledge that whatever the View does with this status (and it’s no concern of the ViewModel what it *does* do), it will always need the colour, so the VM could do the Colour transformation directly… this is possibly not quite as pure, because the VM is dictating to the View “Here’s a status represented as a colour”, and maybe the View wanted to represent status as shapes or number of stars on a star chart, or something else…
Underlying all this is the core concept: The ViewModel is the bridge between the Model and the View; I think of it as the Model *for* the View, although it can be thought of as the View for the Model…
In either event, I’m trying to keep focussed on separation of concerns; and it strikes me that a ViewModel should not be concerned with application-level stuff like state, or navigation.
I recently wrote this on a StackOverflow question…. (shameless plug: feel free to upvote it!)
For example, imagine your app has a login screen, so you create a LoginView, which contains a username and password; probably an OK button and a Cancel button.
You create a LoginViewModel class to bind this view and handle the logic of the login within this class.
But once the app is logged in, it is not the responsibility of the login ViewModel to know where to go next; or which View to render next.. maybe you want to navigate to the last screen this user was on the previous time they were logged in? Maybe it goes to a default screen, as per the User’s profile? This decision is nothing to do with the login function…
So you create a Controller class, something to know all about what state the application is in: Has the user logged in? What screen should follow next, and you can: Instantiate an instance of the LoginViewModel class, then depending on the login result, apply business rules as required to remove the LoginViewModel from scope, and create a new ViewModel, (e.g. HomePageViewModel) etc…
* As a side note, of course, we’ll need to let the app know which Views to use for each VM using DataTemplates.
So I’ve re-factored my code again, and I’ve renamed my MainwindowViewModel, “ApplicationController”, and put those bits of it concerned with furnishing the MainWindowView into a separate ViewModel class, and all that remains is the code concerned with controlling the app as a whole.
I think that this is doing things properly, but as always, my mind is open to change, and I have CodeRush primed and ready to go, should the need for yet another re-factoring arise…
Understanding the Salesforce APIs
Josh Smith is a legend
I’m creating a Salesforce Studio, and I’m doing it in WPF. Despite the fact that .net 3.0 was introduced to us back in 2006 (or ~25 Internet years ago), one still feels like a pioneer when creating something in WPF. Why have the development community (by and large) not accepted the technology to the same extent as its sister platform, WCF? Who can say? Certainly the much-documented ‘learning curve’ is reasonably steep – but it is undoubtedly a journey worth taking.





