Archive for July, 2008
What would you like to see in a WPF diagramming component?
Tagged as WPFWe’ve been doing some customer projects with WPF which have involved a bit of diagramming and visualization work, and we’re now beginning to build some of that work out into a developer component. We’ve got some ideas about what should be in the product based on our experience, but diagramming is a very wide topic, and we know our experiences only scratches the surface of what is possible! So we’re keen to hear from the community what you’d like to see in a diagramming component. What sort of use cases might you have for such a product? What features would it absolutely have to have? What features would you really like to see above those core necessities? What type of diagrams do you want to be creating?
We are currently undertaking prototyping work so getting feedback during this stage has a direct impact on the final product and means we can factor in your feedback more easily.
If you’ve got an opinion, a suggestion or a request, post in the comments or email us via the contact form!
More about heterogeneous MulticolumnTreeViews
I wrote before about heterogeneous hierarchies in the WPF Elements MulticolumnTreeView (aka TreeListView). In that example, I assumed that, although the hierarchy was made up of different types of objects, the set of columns made sense across all the types, or specifically that the columns could be bound in the same way across all the types — in that example, that each type had an EnglishName and a LatinName property. But what if that’s not the case?
For example, consider a simple contact management application, with just two types, Company and Person. For our columns, we might have Name, Email Address and Notes. This gives us a couple of problems. First, Email Address doesn’t make sense for companies. Second, while a company has a Name property, a person has a FirstName and a LastName property, so our Name column is going to need to have different bindings.
The solution for columns that don’t have a consistent binding is to set the column’s CellTemplateSelector rather than its CellTemplate or DisplayMemberBinding. The CellTemplateSelector is a DataTemplateSelector, which means we can dispatch off to different templates as required. In our case, we need two selectors. The Email Address selector selects an empty template for a Company object, and a simple binding for a Person object. The Name selector selects a simple Name binding for a Company object, and a more complex data template for Person objects. Let’s get those templates out of the way first:
<DataTemplate x:Key="EmptyTemplate"> <TextBlock /> </DataTemplate> <DataTemplate x:Key="DefaultNameTemplate"> <TextBlock Text="{Binding Name}" /> </DataTemplate> <DataTemplate x:Key="PersonNameTemplate"> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding FirstName}" /> <TextBlock Text=" " /> <TextBlock Text="{Binding LastName}" /> </StackPanel> </DataTemplate> <DataTemplate x:Key="DefaultEmailAddressTemplate"> <TextBlock Text="{Binding EmailAddress}" /> </DataTemplate>
What about our selectors? Looking at them, the logic of both selectors is exactly the same — select based on type of object. Only the choice of templates is different. So we can make the choice of templates part of the selector’s instance data. In our XAML we will then create two selector instances, but of the same type. Here’s a first pass at the selector design:
public class EntityTypeTemplateSelector : DataTemplateSelector { public DataTemplate DefaultTemplate { get; set; } public DataTemplate PersonTemplate { get; set; } public DataTemplate CompanyTemplate { get; set; } public override DataTemplate SelectTemplate(object item, DependencyObject container) { if (item is Person) { return PersonTemplate ?? DefaultTemplate; } if (item is Company) { return CompanyTemplate ?? DefaultTemplate; } return DefaultTemplate; } }
Notice the fallback to DefaultTemplate if no specific template is defined for a type. In our two-type model, this is almost superfluous, but if we started adding more types to the hierarchy, and found that most of them had a Name property, it would save us having to mention DefaultNameTemplate against every type.
(You may find it objectionable that this selector is specifically coupled to the Company/Person model. Can’t we parameterise it by type as well, so that we only ever have to write the selector once, and set up the type-template mapping in the instance data? Yes we can, but it makes the XAML a bit more verbose. We’ll look at this in a moment.)
With this selector defined, we can now create instances in our XAML:
<local:EntityTypeTemplateSelector x:Key="NameSelector" PersonTemplate="{StaticResource PersonNameTemplate}" DefaultTemplate="{StaticResource DefaultNameTemplate}" /> <local:EntityTypeTemplateSelector x:Key="EmailAddressSelector" CompanyTemplate="{StaticResource EmptyTemplate}" DefaultTemplate="{StaticResource DefaultEmailAddressTemplate}" />
All that remains is to tell our MulticolumnTreeView to use these selectors instead of static templates or bindings:
<ms:MulticolumnTreeView ItemTemplate="{StaticResource People}"> <ms:MulticolumnTreeView.Columns> <GridViewColumn Header="Name" CellTemplateSelector="{StaticResource NameSelector}" /> <GridViewColumn Header="Email Address" CellTemplateSelector="{StaticResource EmailAddressSelector}" /> <GridViewColumn Header="Notes" DisplayMemberBinding="{Binding Notes}" /> </ms:MulticolumnTreeView.Columns> </ms:MulticolumnTreeView>
Our heterogeneous hierarchy is now displaying heterogeneous properties.
I want to come briefly back to the idea of a more reusable selector. This is pretty easy to write: the only trick is to apply ContentPropertyAttribute so that the type-template mappings can appear as direct children of the selector element in XAML. (A real implementation would do some error checking as well, specifically to handle null references.)
[ContentProperty("Templates")] public class EntityTypeTemplateSelector : DataTemplateSelector { private List<TypeTemplate> _templates = new List<TypeTemplate>(); public List<TypeTemplate> Templates { get { return _templates; } } public DataTemplate DefaultTemplate { get; set; } public override DataTemplate SelectTemplate(object item, DependencyObject container) { foreach (TypeTemplate tt in Templates) { if (tt.Type.IsAssignableFrom(item.GetType())) { return tt.Template; } } return DefaultTemplate; } } public class TypeTemplate { public Type Type { get; set; } public DataTemplate Template { get; set; } }
Using it, however, is a little bit fiddlier:
<local:EntityTypeTemplateSelector x:Key="NameSelector" DefaultTemplate="{StaticResource DefaultNameTemplate}"> <local:TypeTemplate Type="cm:Person" Template="{StaticResource PersonNameTemplate}" /> </local:EntityTypeTemplateSelector> <local:EntityTypeTemplateSelector x:Key="EmailAddressSelector" DefaultTemplate="{StaticResource DefaultEmailAddressTemplate}"> <local:TypeTemplate Type="cm:Company" Template="{StaticResource EmptyTemplate}" /> </local:EntityTypeTemplateSelector>
There’s a bit more noise here, and automated tools like Visual Studio Intellisense won’t be able to support the way they could on the version with a hardwired template set. (This might be a consideration depending on your team and workflow. Developers may not mind entering type names. Graphic designers might prefer you gave them a fixed set of “blanks” to fill in.) It’s undoubtedly more reusable, though, and won’t need to be updated whenever the model changes. So which is the right option depends on your application and your project structure.
Choosing WPF Property Grid editors from code
We had a question from a customer recently about how, in the WPF Property Grid, to choose an editor at runtime using code, rather than declaring it once and for all in the XAML. An example might be that only certain users are allowed to edit certain properties: it would be nice to display these properties as read-only to unauthorised users, so that they don’t try to edit them and get “punished” with an error message.
There are a couple of ways to do this, and I thought it might be interesting to share them. Perhaps the simplest and most basic is just to assign the editor in code rather than in the XAML:
DataTemplate template = (DataTemplate)(FindResource(PropertyGrid.ReadOnlyDisplayKey)); if (Environment.UserName == "Ivan") { template = (DataTemplate)(FindResource(PropertyGrid.SimpleTextEditorKey)); } PropertyEditor editor = new PropertyEditor(); editor.DeclaringType = typeof(Person); editor.PropertyName = "Surname"; editor.EditorTemplate = template; pg.Editors.Add(editor);
The only trick here is the use of FindResource to refer to the editor templates (whether built-in or custom).
This works fine, but it’s not idiomatic WPF, because the choice of UI is bundled up with the authorisation code in the code-behind, rather than expressed in the XAML. (Of course, refactoring the code would improve this, but it still leaves you with the situation that someone looking at the XAML won’t see that the Surname property has a PropertyEditor associated with it.) Can we find a more XAML-friendly approach?
Dynamism in WPF templates is achievable in two main ways: triggers and selectors. In this example, it’s probably okay to use a selector, because the user’s authorisation status is unlikely to change while the grid is up. (This assumption might fail if, for example, a supervisor could temporarily authorise the user to make changes by typing in a manager password. But let’s not worry about that.) The selector is easy to write:
public class DynamicTemplateSelector : DataTemplateSelector { public DataTemplate EditableTemplate { get; set; } public DataTemplate ReadOnlyTemplate { get; set; } public override DataTemplate SelectTemplate(object item, DependencyObject container) { // pretend this is impenetrable security code if (Environment.UserName == "Ivan") { return EditableTemplate; } else { return ReadOnlyTemplate; } } }
and easy to declare in the Window.Resources section:
<local:DynamicTemplateSelector
x:Key="DynamicTemplateSelector"
EditableTemplate="{StaticResource {x:Static ms:PropertyGrid.SimpleTextEditorKey}}"
ReadOnlyTemplate="{StaticResource {x:Static ms:PropertyGrid.ReadOnlyDisplayKey}}"
/>To put our DataTemplateSelector to work, we need an element that understands template selection. ContentControl is the element that allows us to present objects using data templates without introducing any UI of its own, so we’ll use that:
<DataTemplate x:Key="DynamicTemplate"> <ContentControl Content="{Binding}" ContentTemplateSelector="{StaticResource DynamicTemplateSelector}" /> </DataTemplate>
Note that the Content property is set to {Binding}, not to the more usual Value. This is because whichever template gets selected by the selector will be looking for the Value property on whatever it gets given, so we don’t need to (in fact, mustn’t) extract the Value ourselves.
Finally, we can now assign this template to the properties we want to mark as read-only to selected users:
<ms:PropertyGrid.Editors> <ms:PropertyEditor PropertyName="FirstName" EditorTemplate="{StaticResource DynamicTemplate}" /> </ms:PropertyGrid.Editors>
The property grid will now display the property as read-only or editable depending on the authorisation criteria in the selector.
In some situations, you could also use smart editors for this. For example, you could create a smart editor whose CanEdit implementation returns true if the user is not authorised. This could then be hooked up to the read-only template. By injecting this smart editor at the top of the editor chain, it would get first dibs on any properties the user wasn’t authorised to edit, while properties the user was authorised to edit would pass down the chain, presumably to find an appropriate read-write editor. The advantage of this approach is that you don’t need to specify individual properties; its disadvantages are that it is a very broad brush, and that it creates a nasty dependency on the order of editor declarations (see the smart editors post for why).
Needless to say, what we’ve shown here is no substitute for proper business layer logic in the underlying objects. If certain users shouldn’t be allowed to edit certain properties, then the business layer should check authorisation before allowing a change to take effect. What the above techniques do give us is a way to surface this business logic in the user interface, give users clear feedback about what they can and cannot do, and protect them from errors.
Mindscape partner conference update
Tagged as EventsWith one day left at the Microsoft Worldwide Partner Conference it seems appropriate to make an update on how the event is going for us.
Overall observations and thoughts:
- The event is huge, there is significant opportunities to get feedback from people who may have never seen your products and who are often key decision makers – feedback on pricing, what benefits they expect to see etc is easily accessible
- The New Zealand connection has been a hit – I was dubious of the effect it would have but it has worked well with a large number of people actively seeking out the NZ stand and loving the t-shirts. It’s been fantastic to have NZ attendees who aren’t exhibiting all wearing the t-shirts which effectively advertise the stand – thanks!
- The organisation and logistics are impressive – so far everything has been done effectively flawlessly which is amazing given the scale
A quick snap of the Mindscape part of the NZ stand:
Tomorrow is the last day and with that we’ll be dismantling at the end of the day and heading back to New Zealand on Friday, arriving on Sunday.
I’d urge other companies to get involved with the WPC in future if they possibly can. Now, back to preparing to meet more new people!
What’s coming in LightSpeed 2.1?
LightSpeed 2.0 has been out the door for a short while now and we have been receiving some fantastic feedback so we thought now would be a good time for a quick sneak-peak at what’s coming in 2.1:
Full text indexing support
Sometimes SQL doesn’t provide the free text searching capabilities that you need (or perhaps your selected database engine has no full text indexing support). LightSpeed 2.1 resolves this by providing a pluggable full text search API and ships with a Lucene.NET provider so that no matter what database engine you’re using, you always have access to extremely fast full text search capabilities.
VistaDB, SQL Server Compact 3.5 and Firebird support
Several customers asked about supporting database engines outside of the 5 that LightSpeed already supported (SQL Server, Oracle, PostgreSQL, MySQL, SQLite) so we’ve added support for them as well. This means that developers can now leverage our powerful LINQ capabilities when working with VistaDB, SQL Server Compact 3.5 and Firebird.
Improved Designer Support
We have been very impressed by the number of users finding the LightSpeed design surface helpful in building rich domain models and have focused on improvements to performance and features.
Delete Queries
With LightSpeed 2.1 you no longer need to fetch an entity to be able to delete it – simply pass in a query object to delete all records that match that query.
Why tell you now what’s coming up?
For starters, as we add things to LightSpeed for 2.1 they become available to customers in the nightly builds and therefore it can be useful to them to know what cool new features they’re getting free each night.
Secondly, we hope to make new potential users aware of what they will be getting if they become a customer now (all our point releases are free and therefore if you buy today you can start using these features as soon as they become available).
To start working with some of these features download the latest nightly build here (or customers can download the latest nightly build of their licensed version from the store).
![]()
BrainDump (1)
Community Code (1)
Events (6)
General (31)
Lab Samples (2)
LightSpeed (132)
MegaPack (3)
News (48)
Products (64)
Projects (4)
Screencast (6)
SharePoint (1)
Silverlight (5)
Silverlight Elements (12)
SimpleDB Management Tools (11)
Visual Studio (4)
VS File Explorer (5)
WPF (31)
WPF Diagramming (14)
WPF Elements (22)
WPF Property Grid (24)
![]()
June 2010
May 2010
April 2010
March 2010
February 2010
January 2010
December 2009
November 2009
October 2009
September 2009
August 2009
July 2009
June 2009
May 2009
April 2009
March 2009
February 2009
January 2009
December 2008
November 2008
October 2008
September 2008
August 2008
July 2008
June 2008
May 2008
April 2008
March 2008
February 2008
January 2008
December 2007
November 2007
September 2007
August 2007
July 2007
June 2007
May 2007
April 2007
March 2007





Posted by Ivan Towlson on 31 July 2008



