Archive for March, 2008
Testing WPF controls in NUnit
Tagged as WPFYou can instantiate and test WPF controls in a NUnit test in the usual way:
MyTestControl control = new MyTestControl(); Assert.AreEqual(someValue, control.MyProperty);
This will appear to work wonderfully until you run it as part of your automated build, at which point it will fail on the first line, complaining that UIElements have to be created in the STA.
This happens because when you’re running the tests, you’re probably using the NUnit GUI or TestDriven.NET, which run their tests on a STA thread, but the build server is probably using the NUnit console, which runs tests on a MTA thread.
You can fix this by creating an app.config file in your test project with the following content:
NUnit will now run all tests in the STA, regardless of GUI or console environment. Your tests can now create UIElements and controls as required.
Triggers and selectors in WPF templating
If you’ve worked with WPF for any significant length of time, you’ll be used to using styles and templates to describe how to present an object in the user interface. But what if you want to have the presentation change according to circumstances? WPF provides two ways of doing this: triggers and selectors.
Triggers provide a way to selectively modify the presentation based on data values. For example, a trigger could specify that an Image element should be hidden if the Picture property is null, or that a TextBlock should be drawn in grey if the IsEnabled property is false.
Selectors allow more complex logic and more radical changes. A selector allows you to choose different DataTemplates or Styles depending on custom logic. For example, in a heterogeneous ItemsControl, you might choose whether to use a TextBlock or TextBox-based template depending on whether the item is read-only or read-write.
Superficially this makes selectors an attractive option when the different presentations have got substantially different structure, or when the logic for when the different presentations should be used is more complicated than “some property equals some value.” But there’s a catch with selectors that means you can only use them in very specific cases.
The problem is that selectors run only once, when WPF has to determine a template for the object. After that, it’s up to the template to update itself, using triggers. So a selector should only consider immutable aspects of the object. For example, it’s appropriate for a selector to consider the type of the object, or a read-only discriminator. But if you use a selector to switch templates depending on whether the BankBalance property is positive or negative, you’ll be in for a disappointment. If the BankBalance value starts out as positive, then changes to negative, any controls that have already selected the “positive” template will continue to display the “positive” template. By contrast, if you’d used a single template with triggers, the “negative” settings would have been applied when the BankBalance went negative.
This might seem to put you in a bind if you want the template to update as data changes, but need more sophisticated logic than the “does some property equal some value” which is all that triggers support.
Fortunately, you can get around this by using a DataTrigger. Although a DataTrigger still performs an equality test, you can use an IValueConverter to convert the raw value into a classifier that you can then match for equality. For example, you could write an IsNegativeValueConverter which returns true for negative values and false for non-negative values. Your DataTrigger can then have a Binding of {Binding BankBalance, Converter={…}}, with a Value of true to activate the “negative” setters.
This works fine for DataTemplates, but what about Styles or ControlTemplates? Suppose you want to style a TextBox so that it turns red if its Text property, considered as a number, is negative? Well, DataTrigger will still do the job, but you need to find the right binding source. In this case, RelativeSource.Self gives you access to the control being styled or templated. So in our Style.Triggers or ControlTemplate.Triggers collection, we would create a DataTrigger with a Binding of {Binding Text, RelativeSource={RelativeSource Self}, Converter={…}}.
This does seem a bit unnatural: why should we use a plain Trigger for simple matches and a DataTrigger with a magic binding for more complex matches? It would be nice if some future version of WPF supported converters on plain Triggers. But for now the DataTrigger/RelativeSource.Self trick allows us to realise the sophisticated logic of selectors in the live world of triggers.
WANTED: LINQ-to-LightSpeed beta testers
Tagged as LightSpeedOne of the key features of LightSpeed 2.0 will be the inclusion of a LINQ provider for working with LightSpeed entities. LINQ is a great new way of expressing queries that Microsoft have delivered with .Net 3.5 (for more information, read the wikipedia article here). Having said that, writing a LINQ provider is no easy task and because of that we’re looking for people to beta test and really knock it around.
What we want to hear about:
- Any bugs you come across
- Feedback on performance
- Feedback on LINQ samples
- Feedback on the completeness of the implementation
- Anything you feel would be useful :-)
If you’re interested in joining the beta program then send me an email: jd@mindscape.co.nz
Thanks,
– JD
P.S. LightSpeed will be remaining a .Net 2.0 product for the time being – LINQ support is added by referencing an additional assembly in your .Net 3.5 projects.
Eager Loading
Tagged as LightSpeedLightSpeed was designed to provide flexibility to developers that want to have fine grained control how how eager and lazy loading works. This post highlights how basic loading can be manipulated and then covers some of the more advanced load graph management features in LightSpeed.
Always Lazy Loading
If an association has no EagerLoad attribute applied to it, by default, it will be lazily loaded.
private readonly EntityCollection _users = new EntityCollection();
Always Eager Loading
By specifying an EagerLoad attribute with no parameters, the association will always be eagerly loaded.
[EagerLoad] private readonly EntityCollection _users = new EntityCollection();
Eager Loading Based on Aggregate Name
If an association has an EagerLoad attribute specified, with an AggregateName parameter on it, the association will only be eagerly loaded if the Query object has the same value for AggregateName. If the values are different, the association will be lazily loaded.
[EagerLoad(AggregateName = "Detail")] private readonly EntityCollection _users = new EntityCollection();
Then, it is just a matter of setting the AggregateName property.
query.AggregateName = "Detail"; // Causes the _users association to be eager loaded. query.AggregateName = "NotDetail"; // Causes the _users association to be lazy loaded.
Named Aggregates provide an extremely flexible way of managing eager load graphs. To make this feature even more powerful, multiple named aggregates can be applied to a single field. This powerful feature is just one of the many ways that LightSpeed is different and more effective than many other frameworks that exist.
– JD
![]()
BrainDump (1)
Community Code (1)
Events (7)
General (34)
Lab Samples (2)
LightSpeed (144)
MegaPack (3)
News (52)
NHibernate Designer (4)
Products (68)
Projects (4)
Screencast (6)
SharePoint (2)
Silverlight (7)
Silverlight Elements (14)
SimpleDB Management Tools (12)
Visual Studio (4)
VS File Explorer (6)
WPF (34)
WPF Diagramming (17)
WPF Elements (30)
WPF Property Grid (26)
![]()
August 2010
July 2010
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 25 March 2008


