Saturday, April 12, 2008

Someone on the CSLA .NET discussion forum recently asked what new .NET 3.5 features I used in CSLA .NET 3.5. The poster noted that there are a lot of new features in .NET 3.5, which is true. They also included some .NET 3.0 features as "new", though really those features have now been around for 15 months or so and were addressed in CSLA .NET 3.0. CSLA .NET 3.0 already added support for WCF, WPF and WF, so those technologies had very little impact on CSLA .NET 3.5.

My philosophy is to use new technologies only if they provide value to me and my work. In the case of CSLA .NET this is extended slightly, such that I try to make sure CSLA .NET also supports new technologies that might be of value to people who use CSLA .NET.

While .NET 3.5 has a number of new technologies at various levels (UI, data, languages), many of them required no changes to CSLA to support. I like to think this is because I'm always trying to look into the future as I work on CSLA, anticipating at least some of what is coming so I can make the transition smoother. For example, this is why CSLA .NET 2.0 introduced a provider model for the data portal - because I knew WCF was coming in a couple years and I wanted to be ready.

Since CSLA .NET already supported data binding to WPF, Windows Forms and Web Forms, there was no real work to do at the UI level for .NET 3.5. I actually removed Csla.Wpf.Validator because WPF now directly supplies that behavior, but I really didn't add anything for UI support because it is already there.

Looking forward beyond 3.5, it is possible I'll need to add support for ASP.NET MVC because that technology eschews data binding in favor of other techniques to create the view - but it is too early to know for sure what I'll do in that regard.

Since CSLA .NET has always abstracted the business object concept from the data access technique you choose, it automatically supported LINQ to SQL (and will automatically support ADO.NET EF too). No changes required to do that were required, though I did add Csla.Data.ContextManager to simplify the use of L2S data context objects (as a companion to the new Csla.Data.ConnectionManager for raw ADO.NET connections). And I enhanced Csla.Data.DataMapper to have some more powerful mapping options that may be useful in some L2S or EF scenarios.

LINQ to Objects did require some work. Technically this too was optional, but I felt it was critical, and so there is now "LINQ to CSLA" functionality provided in 3.5 (thanks to my colleague Aaron Erickson). The primary feature of this is creating a synchronized view of a BusinessListBase list when you do a non-projection query, which means you can data bind the results of a non-projection query and allow the user to add/remove items from the query result and those changes are also reflected in the original list. As a cool option, LINQ to CSLA also implements indexed queries against lists, so if you are doing many queries against the same list object you should look into this as a performance booster!

So all that's left are some of the language enhancements that exist to support LINQ. And I do use some of them - mostly type inference (which I love). But I didn't go through the entire body of existing code to use the new language features. The risk of breaking functionality that has worked for 6-7 years is way too high! I can't see where anyone would choose to take such a risk with a body of code, but especially one like CSLA that is used by thousands of people world-wide.

That means I used some of the new language features in new code, and in code I had to rework anyway. And to be honest, I use those features sparingly and where I thought they helped.

I think trying to force new technologies/concepts/patterns into code is a bad idea. If a given pattern or technology obviously saves code/time/money or has other clear benefits then I use it, but I try never to get attached to some idea such that I force it into places where it doesn't fit with my overall goals.

Saturday, April 12, 2008 3:11:52 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [2]  | 

 Sunday, March 09, 2008

I'm just back from the MIX 08 conference. This was the first conference I've attended in many years (around 10 I think) where I wasn't speaking or somehow working. I'd forgotten just how fun and inspiring it can be to simply attend sessions and network with people in the open areas. No wonder people come to conference!! :)

Not that it was all fun and games. I did have meetings with some key Microsoft people and Scott Hanselman interviewed me for an upcoming episode of Hanselminutes (discussing the various data access and ORM technologies and how they relate to CSLA .NET 3.5).

The Day 1 keynote was everything I'd hoped for.

Well, nearly. The first part of the keynote was Ray Ozzie trying to convey how Microsoft and the web got to where it is now. The goal was to show the vision they are pursuing now and into the future, but I thought the whole segment was rather flat.

But then Scott Guthrie came on stage and that was everything you could hope for. Scott is a great guy, and his dedication and openness seem unparalleled within Microsoft. I remember first meeting him when ASP.NET was being unveiled. At that time he seemed so young and enthusiastic, and he was basically just this kick-ass dev who'd created the core of something that ultimately changed the Microsoft world. Today he seems nearly as young and easily as enthusiastic, and he's overseeing most of the cool technologies that continue to change the Microsoft world. Awesome!

So ScottGu gets on stage and orchestrates a keynote that really illustrates the future of the web. Silverlight (which makes me SOOoooo happy!), IE8, new data access technologies (like we needed more, but they are still cool!) and things like ASP.NET MVC and more.

As I expected, they released a whole lot of beta code. You can get a full list with links from Tim Sneath's blog. He also has links to some getting started materials.

The real reason for keynotes though, is to inspire. And this keynote didn't disappoint. The demos of Silverlight and related technologies were awesome! There was some funny and cute banter with the casting director from Circ del Sole as she demonstrated using a cool disconnected WPF app. There was a fellow RD, Scott Stanfield, showing integration of SeaDragon into Silveright so we can look (in exquisite detail) at the memorabilia owned by the Hard Rock Cafe company, some thought-provoking demos of Silverlight on mobile devices and more.

Now to be honest, I've never been a fan of the web development model. Having done terminal-based programming for many years before coming to Windows, I find it hard to get excited about returning to that ancient programming model. Well, a worse one actually, because at least the mainframe/minicomputer world had decent state management...

AJAX helps, but the browser makes for a pretty lame programming platform. It is more comparable perhaps to an Apple II or a Commodore 64 than to a modern environment, and that's before you get into the inconsistencies across browsers and that whole mess. Yuck!

Which is why Silverlight is so darn cool! Silverlight 2.0 is really a way to do smart client development with a true web deployment model. Much of the power of .NET and WPF/XAML, with the transparent deployment and cross-platform capabilities of the browser world. THIS is impressive stuff. To me Silverlight represents the real future of the web.

It should come as no surprise then, that I spent my time in Silverlight 2.0 sessions after the keynote. Sure, I've been working (on and off) with Silverlight 1.1/2.0 for the past several months, but it was a lot of fun to see presentations by great speakers like Joe Stegman (a Microsoft PM) and various other people.

One of the best sessions was on game development with Silverlight. I dabble in game development whenever I have spare time (not nearly as much as I'd like), and so the talk was interesting from that perspective. But many of the concepts and techniques they used in their games are things designers and developers will likely use in many other types of application. Background loading of assemblies and content while the app is running, and some clever animation techniques using pure XAML-based concepts (as opposed to some other animation techniques I saw that use custom controls written in C#/VB - which isn't bad, but it was fun to see the pure-XAML approaches).

Many people have asked about "CSLA Light", my planned version of CSLA .NET for Silverlight. Now that we have a Beta 1 of Silverlight I'll be working on a public release of CSLA Light, based on CSLA .NET 3.5. Microsoft has put a lot more functionality into Silverlight 2.0 than they'd originally planned - things like data binding, reflection and other key concepts are directly supported. This means that the majority of CSLA can be ported (with some work) into Silverlight. The data portal is the one big sticking point, and I'm sure that'll be the topic of future blog posts.

My goal is to support the CSLA .NET 3.5 syntax for property declaration and other coding constructs such that with little or no change you can take a business class from full CSLA and have it work in CSLA Light. This goal excludes the DataPortal_XZY implementations - those will almost always be different, though if you plan ahead and use a DTO-based data access model even that code may be the same. Of course time will tell how closely I'll meet this goal - but given my work with pre-beta Silverlight 2.0 code I think it is pretty realistic.

Scott Guthrie indicated that Silverlight 2.0 Beta 1 has a non-commercial go-live license - right now. And that Beta 2 would be in Q2 (I'm guessing June) and would have a commercial go-live license, meaning it can be used for real work in any context.

The future of the web is Silverlight, and Beta 1 is the start of that future. 2008 is going to be a great year!

Sunday, March 09, 2008 5:18:27 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  | 

 Monday, March 03, 2008

Another place where I was able to reduce business object code in CSLA .NET 3.5 was to effectively eliminate the GetIdValue() method.

Prior to version 3.5, GetIdValue() was required, and you had to provide a unique value identifying your object. This value was used to implement Equals() and GetHashCode(), and was used as the ToString() value. This was good, because it enabled the concept of logical equality, where objects were equal to each other based on their id value.

For better or worse, WPF doesn't support logical equality. They only support absolute equality - ideally implemented by comparing all properties of the two objects so two objects are only equal if all their properties are equal. A poor man's replacement is to use reference equality - which is much faster but is technically less accurate. The effective default in .NET is reference equality.

CSLA .NET 3.5 no longer overrides Equals() or GetHashCode(), so it now uses the .NET default behavior. This makes WPF happy. This might break some people's existing code (though a poll on the forum indicates it is a non-issue for virtually everyone), because there is no longer any idea of logical equality unless you implement it yourself.

The upside though, is that you no longer need to override GetIdValue(). I left the method in the framework for backward compatibilty, so if you do override it your code will continue to compile (though the value is now only used in a ToString() override).

Monday, March 03, 2008 8:53:36 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [3]  | 

 Wednesday, February 27, 2008

I'm psyched! I finally figured out how to get the Csla.Wpf.CslaDataProvider control to support a Delete command that removes child items from a databound list object.

As you might expect, the answer to the problem was staring me in the face the whole time - I just didn't see it. Isn't that the way things often work? ;)

Since day one, CslaDataProvider has support the Save, Undo and AddNew commands (using XAML commanding), so it has been possible to create Save, Cancel and Add buttons on a form purely through XAML - no code-behind required at all.

Now, with this new change it is also possible to implement a Remove button in a DataTemplate with no code-behind. The button can use the standard Delete command to tell the CslaDataProvider managing the BusinessListBase object to remove the child object bound to that row in the DataTemplate. The XAML looks like this:

<DataTemplate x:Key="lbTemplate">
  <Grid>
    <StackPanel Orientation="Horizontal">
      <TextBlock>Id:</TextBlock>
      <TextBox Text="{Binding Path=Id, Converter={StaticResource IdentityConverter}, ValidatesOnDataErrors=True}" Width="100" />
      <TextBlock>Name:</TextBlock>
      <TextBox Text="{Binding Path=Name, Converter={StaticResource IdentityConverter}, ValidatesOnDataErrors=True}" Width="250" />
      <Button
        Command="ApplicationCommands.Delete"
        CommandParameter="{Binding}"
        CommandTarget="{Binding Source={StaticResource RoleList}, Path=CommandManager, BindsDirectlyToSource=True}"
        HorizontalAlignment="Left">Remove</Button>
    </StackPanel>
  </Grid>
</DataTemplate>

The key was realizing that the CommandParameter could be bound to the entire object that is represented by this DataTemplate - the individual row object. This revelation meant that the CslaDataProvider control can in fact remove that item because an equality comparison is possible. So ApplicationCommands.Delete passes the child object reference to the data provider, which removes the item from the databound list object and that's it!

So this means you can now create a typical maintenance screen with no code behind the XAML. None. You have to write zero lines of VB/C#. Too cool!!

And it means that even on a more complex screen you still don't need to write save/cancel/add new/remove code. That's a lot of code savings! Often all you need to write is code dealing with navigation from this screen to some other screen, perhaps some exception handling code (which I put in a base class) and some authorization code to provide visual cues to the user about what they can and can't do.

Is this really the final step? I doubt it. I already have some ideas on how to expose the authorization knowledge encapsulated by the business object such that it can be directly used within the XAML. I don't know if I'll get that working, but if I can reduce/elminate the UI authorization code (that provides visual cues to the user) and get that into XAML then even more forms will become codeless.

Wednesday, February 27, 2008 8:41:14 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [1]  | 

 Tuesday, January 22, 2008

in a recent email thread someone was wondering why component vendors are being so slow in coming out with grid controls for WPF/XAML.

One obvious reason is that grid controls are hard to build, and WPF/XAML is radically different from Windows Forms or Web Forms. But still, it is fair to wonder why these highly experienced control vendors haven't overcome that challenge.

I think the reason is that technology isn't the issue. At least not in the raw "learn how to use XAML" way. I think the real issue is much bigger!

Consider the incredible risk a vendor would assume by creating a grid control now.

Microsoft hasn’t come out with a WPF grid, and so there are no standard interfaces in .NET to support data binding to a grid. Certainly the current interfaces used by WPF are not nearly powerful enough to get in-place grid editing like we have in Windows Forms – and that’s a requirement if WPF is ever going to replace Windows Forms for business development.

Windows Forms and Web Forms both have benchmark grids from Microsoft. They set the standard, and define the core interaction used by data binding. The other vendors can then build around that core to do cool stuff. In particular, Windows Forms defines a whole set of powerful interfaces to allow in-place editing so the user can navigate freely in a grid, edit cells, add rows and delete rows – and press ESC to cancel changes to whatever row they are on. All features most users would consider critical to the in-place experience. The majority of those interfaces are not used by WPF today!! Nor does WPF have replacements for them. And if they do replace those interfaces then you can’t bind to a DataTable, which shuts out most developers from WPF again – probably a bad idea.

The WPF team has already shown that they’ll supersede existing interfaces (INotifyCollectionChanged was invented even though IBindingList was already there). So it is somewhat hard to predict where Microsoft might go in this regard. It is quite possible they’ll do the “worse of all worlds” and support the DataTable (all the existing Windows Forms interfaces) and invent a whole new model as well… (again, see INotifyCollectionChanged – invented for WPF, but IBindingList is also fully supported by WPF)

So in WPF the poor component vendors are really stuck. There’s no defined standard for this kind of data binding, so they need to invent it. They’ll each invent something different from the other vendors – and NONE of them will likely match whatever Microsoft eventually does. That means they are all in deep trouble when Microsoft does set the standard. And so are all consumers of those grids (all of us!).

This is very much like pre-ODBC database access, except in this case it is a very safe bet that “ODBC” is coming (in the form of some standard grid definition) and so investing in building a proprietary solution is a known dead-end. A waste of money and very likely a way to make many, many angry customers who may hate you forever.

Nasty business just now… :(

WPF
Tuesday, January 22, 2008 12:17:53 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [7]  | 

 Wednesday, December 19, 2007

I've been working all day on this WPF/WCF application, mostly trying to figure out how to configure WCF to actually do what I want in terms of security and authentication. All those angle brackets from the config files have given me a splitting headache... WCF may be cool, but configuring even relatively simple security scenarios is ridiculously difficult.

And then distaster struck. As though fighting with WCF and SSL wasn't enough, VS 2008 decided to quit publishing my app for ClickOnce. In order to test this app, I need to publish for ClickOnce on my dev box, copy the results to a test server and then run the code on a test client (thankfully we live in an age of virtual machines!!).

So the failure to publish to ClickOnce brought me up short. The issue is that the WPF project wouldn't build. It would build and run fine in all other ways, but not when I tried to publish for ClickOnce. It had been publishing just fine, and then BOOM!

(The only thing I can think of is that I was publishing for online only, then I published for online/offline, and then I switched back to online only - maybe VS doesn't like that sort of waffling and wants me to be more decisive?)

The specific problem is that the .g.i.cs files for each XAML source file that should have been in the obj\Debug directory didn't get there. Google was no help - searching for "clickonce publish .g.i.cs obj\Debug could not be found" resulted in one hit - to an MSDN forums post that was unreachable (I kept getting an MSDN forums error page).

Build|Clean Solution had no effect. Shutting down and reopening VS had no effect. Rebooting the dev box had no effect.

Finally I thought to manually delete the obj and bin folders in the project directory. And for good measure I deleted the .user file and .suo file for the project and solution. Then I reopened the project and it how publishes just fine.

Wednesday, December 19, 2007 5:10:22 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [1]  | 

 Tuesday, November 13, 2007

I was recently asked whether CSLA incorporates thread synchronization code to marshal calls or events back onto the UI thread when necessary. The short answer is no, but the question deserves a bit more discussion to understand why it isn't the business layer's job to handle such details.

The responsibility for cross-thread issues resides with the layer that started the multi-threading.

So if the business layer internally utilizes multi-threading, then that layer must abstract the concept from other layers.

But if the UI layer utilizes multi-threading (which is more common), then it is the UI layer's job to abstract that concept.

It is unrealistic to build a reusable business layer around one type of multi-threading model and expect it to work in other scenarios. Were you to use Windows Forms components for thread synchronization, you'd be out of luck in the ASP.NET world, for example.

So CSLA does nothing in this regard, at the business object level anyway. Nor does a DataSet, or the entity objects from ADO.NET EF, etc. It isn't the business/entity layer's problem.

CSLA does do some multi-threading, specifically in the Csla.Wpf.CslaDataProvider control, because it supports the IsAsynchronous property. But even there, WPF data binding does the abstraction, so there's no thread issues in either the business or UI layers.

Tuesday, November 13, 2007 11:09:54 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  | 

I haven't tried this yet, but it looks like a very nice tool for WPF developers:

Woodstock for WPF - The Code Project - Windows Presentation Foundation

WPF
Tuesday, November 13, 2007 10:48:41 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [1]  | 

 Wednesday, October 10, 2007

Earlier this week I co-presented a session at ReMIX in Boston, with Anthony Handley, a fellow Magenicon. Anthony is a User Experience Specialist, and the two of us have been working on a WPF/Silverlight project (that also happens to use CSLA .NET of course :) ) and in this presentation we discussed our experiences using WPF from the perspectives of a developer and a designer.

Here are the links to the video of the session.

Real World Experiences Building Applications Using WPF and Silverlight

Part 1
http://channel9.msdn.com/Showpost.aspx?postid=346810
Part 2
http://channel9.msdn.com/Showpost.aspx?postid=346812
Part 3
http://channel9.msdn.com/Showpost.aspx?postid=346815
Part 4
http://channel9.msdn.com/Showpost.aspx?postid=346818

Wednesday, October 10, 2007 3:10:17 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [2]  | 

In CSLA .NET 3.0 I implemented Csla.Wpf.Validator. This control provides functionality similar to the Windows Forms ErrorProvider control, only in WPF. Of course the ErrorProvider relies on the standard IDataErrorInfo interface, which CSLA supports on behalf of your business objects, and so my Validator control used that same interface.

While I was researching and designing the Validator control, I was in contact with the WPF product team. As a result, I had (shall we say) a "strong suspicion" that my control was a temporary stop-gap until Microsoft provided a more integrated solution. And that's fine - we needed something that worked, and Validator was the ticket.

This blog post provides some good, detailed, insight into the real solution in .NET 3.5: 

Windows Presentation Foundation SDK : Data Validation in 3.5

A couple people have emailed me, asking what I think about this. My answer: I'm happy as can be!

As I say, I knew Validator was temporary. WPF is a version 1.0 technology, and it is very clear that Microsoft will be evolving it rapidly over the next few years. And it is equally clear that WPF must evolve to catch up to, and hopefully exceed, Windows Forms. That means more robust data binding support, including an ErrorProvider equivalent.

So to me, this just means that CSLA .NET 3.5 can drop the Validator control, because there's now a directly supported solution in .NET itself. While this will require changing XAML when moving from .NET 3.0 to 3.5, it is a worthwhile change to make.

Wednesday, October 10, 2007 9:31:01 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [2]  | 

 Friday, September 28, 2007

CSLA .NET version 3.0 adds support for Microsoft .NET 3.0 features. This ~120 page ebook covers how to use these new capabilities:

  • Windows Presentation Foundation (WPF)
    • Creating WPF forms using business objects
    • Using the new controls in the Csla.Wpf namespace
      • CslaDataProvider
      • Validator
      • Authorizer
      • ObjectStatus
      • IdentityConverter
    • Maximizing XAML and minimizing C#/VB code
  • Windows Communication Foundation (WCF)
    • Using the new WCF data portal channel to seamlessly upgrade from Remoting, Web services or Enterprise Services
    • Building WCF services using business objects
    • Applying WCF security to encrypt data on the wire
    • Sending username/password credentials to a WCF service
      • Including use of the new Csla.Security.PrincipalCache class
    • Using the DataContract attribute instead of the Serializable attribute
  • Windows Workflow Foundation (WF)
    • Creating activities using business objects
    • Invoking a workflow from a business object
    • Using the WorkflowManager class in the Csla.Workflow namespace

Version 3.0 is an additive update, meaning that you only need to use the .NET 3.0 features if you are using .NET 3.0. CSLA .NET 3.0 is useful for people using .NET 2.0!! These features include:

  • Enhancements to the validation subsystem
    • Friendly names for properties
    • Better null handling in the RegExMatch rule method
    • New StringMinLength rule method
    • Help for code generation through the DecoratedRuleArgs class
  • Data binding issues
    • Fixed numerous bugs in BusinessListBase to improve data binding behavior
    • Throw exception when edit levels get out of sync, making debugging easier
    • N-level undo changed to provide parity with Windows Forms data binding requirements
  • AutoCloneOnUpdate
    • Automatically clone objects when Save() is called, but only when data portal is local
  • Enhancements to the authorization subsystem
    • CanExecuteMethod() allows authorization for arbitrary methods

CSLA .NET 3.0 includes numerous bug fixes and some feature enhancements that benefit everyone. If you are using version 2.0 or 2.1, you should consider upgrading to 3.0 to gain these benefits, even if you aren't using .NET 3.0.

See the change logs for version 3.0, version 3.0.1 and version 3.0.2 for a more detailed list of changes.

Using CSLA .NET 3.0 is completely focused on how to use the new features in version 3.0. The book does not detail the internal changes to CSLA .NET itself, so all ~120 pages help you use the enhancements added since version 2.1.

Get the book at store.lhotka.net.
(C# available now, VB available in early October)

Download the 3.0.2 code from the CSLA .NET download page.

Books | CSLA .NET | WCF | Workflow | WPF
Friday, September 28, 2007 3:21:26 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  | 

It is a reasonably well-known fact that WPF misuses the Equals() method in the data binding implementation.

If you set a DataContext to an object, then set it to another object that is logically equal to the first, but which has different data, WFP gladly ignores the new object's data:

form.DataContext = A;
B = A.Clone();
B.Value = "new value";
form.DataContext = B;

Assuming A and B retain logical equality even though Value has changed, this code results in the UI not showing the new value. Apparently the reasoning is that if the objects are equal, then there's no need to update any data through data binding.

Of course this totally confuses ReferenceEquals() with Equals(), and the result is that objects used by WFP can no longer have logical equality. They can only have reference equality.

(or, arguably, WPF forces 100% property-level equality across objects, so equality can extend to two different instances as long as they have absolutely no different property values - which seems entirely useless)

In .NET 3.0 I had a solution, at least in CslaDataProvider. The solution was to temporarily set the DataContext to null, then to the new object. The result was that the faulty (imo anyway) equality comparison was defeated.

Unfortunately, it appears that .NET 3.5 may have "fixed a bug" that prevents this from working. The result is that it appears there is NO WAY TO REFRESH DATA when fields of an object change, but the object's logical identity remains the same.

I'm not yet sure of a final solution. The current situation is very bad, because you can either use WPF or you can have logical equality between objects - but not both.

It might be the case that people who need logical equality will have to implement their own parallel Equals() concept - ignoring the standard one built into .NET. That's a really poor solution, but if Microsoft isn't going to use their own framework responsibly then we're kind of stuck. Of course operators become an issue then, since operator overloading is related to Equals() as well. I suppose you could break that relationship, but then you'd get really odd stuff like this:

x = y is true

x.Equals(y) is false

But if WPF forces Equals() to be ReferenceEquals() instead of actual equality, then we come back to being stuck.

I love WPF - it is really cool. But this particular issue is a real problem. Apparently one without a real solution.

WPF
Friday, September 28, 2007 9:02:38 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [6]  | 

 Friday, September 21, 2007

I just got back from VS Live NY - which was a great show. It sold out, and the people attending were very engaged and fun to be with. I love crowds like that!

In my all-day workshop on building distributed apps using objects I showed how to use WPF commanding to automatically enable/disable Save and Cancel buttons on a form by connecting them to a CslaDataProvider control. That's a really cool feature of WPF that I am leveraging with some of the new CSLA .NET 3.0 features.

An attendee asked if it was possible to hide the Save button, not just disable it. I hadn't thought about that, and came up with some answer involving code.

Josh Smith, who was also in the audience, has given this even further thought and sent me an email with a better, pure XAML, solution. Thank you Josh!! Here's the relevant bit of the email:

During the presentation a fellow asked you how, in WPF, to hide a Button when it is disabled.  The Button was disabled because its associated command could not execute, and he wanted to hide the Button instead of letting it sit in the UI disabled.

The solution you gave him involved some code, which threw a red flag in my mind.  IMO, this is the kind of thing you should use XAML to express, so that there are less "moving parts" in your app.  Here's one way to implement that functionality with no code at all:

<Button Command="Open" Content="_Open">
  <Button.Style>
    <Style TargetType="Button">
      <Style.Triggers>
        <Trigger Property="IsEnabled" Value="False">
          <Setter Property="Visibility" Value="Collapsed" />
        </Trigger>
      </Style.Triggers>
    </Style>
  </Button.Style>
</Button>

Depending on your layout, you might want to set Visibility to Hidden instead.

Friday, September 21, 2007 7:01:20 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [1]  | 

 Wednesday, June 20, 2007

A CSLA .NET user, Aaron Nottestad, has been helping test 3.0 and ran into some issues when using the new WPF CslaDataProvider with editable objects. Thanks Aaron!

As a result, I had to do some work with CslaDataProvider, so it can manage the object’s entire lifetime from create/fetch through to save/cancel. If it can’t manage the lifetime, especially the save, then it can’t get the new object that comes back as a result of save. And if it doesn’t get that new object, then neither does data binding, so the UI controls end up editing an old instance of the object.

So the CslaDataProvider now has Save() and Cancel() methods that you can call to trigger saving or canceling of the business object. Also, as the object is created/fetched CslaDataProvider automatically calls BeginEdit() on the object.

This behavior is all optional, and is controlled by the ManageObjectLifetime property of the CslaDataProvider control. So if you want this behavior, you have to set that property to True. If you leave it at False (the default), then you must manage everything through code – though honestly you can’t manage editable objects through code while using CslaDataProvider. So maybe I should make the default be True? Hmm.

Anyway, this was easy enough to do and worked great. The resulting forms had exactly 4 lines of code – 2 to call Save() and 2 to call Cancel(). It occurred to me that there must be a way to avoid writing those 4 lines of boring code, and Aaron put me onto the RoutedCommand concept in XAML.

A RoutedCommand allows a control like a button or menu item to invoke a method on another control – purely through XAML. There are many examples out there about how this works to create standard Copy/Paste menu items that run against the current TextBox control, and that sort of thing. But none that I found which routed a command to a data provider control.

The reason turns out to be that the target of a command must be a UIElement, and data providers don’t inherit from that base class. Oops…

I thought I was stuck, because I really do want to route the command to CslaDataProvider in this case. However, I figured out a solution.

CslaDataProvider now has a read-only CommandManager property. This property exposes a “command manager” object which does inherit from UIElement and which does handle the Save and Undo routed commands. When it is created by CslaDataProvider, it is given a reference to the CslaDataProvider control, so it simply delegates all Save commands to the CslaDataProvider.Save() method and all Undo commands to CslaDataProvider.Cancel().

With that done, you can route a command from a button or menu item (or any other valid command source) to this CommandManager object, which effectively means you’ve routed the command to the CslaDataProvider control.

The CslaDataProvider gets declared like this:

    <csla:CslaDataProvider x:Key="ChildList"

                           ObjectType="{x:Type this:ChildList}"

                           FactoryMethod="GetList"

                           IsAsynchronous="False"

                           ManageObjectLifetime="True">

    </csla:CslaDataProvider>

 

Then the button controls get declared like this:

            <Button

              Command="ApplicationCommands.Save"

              CommandTarget="{Binding Source={StaticResource ChildList},

                              Path=CommandManager, BindsDirectlyToSource=True}"

              HorizontalAlignment="Left" IsDefault="True">Save</Button>

            <Button

              Command="ApplicationCommands.Undo"

              CommandTarget="{Binding Source={StaticResource ChildList},

                              Path=CommandManager, BindsDirectlyToSource=True}"

              HorizontalAlignment="Left" IsCancel="True">Cancel</Button>

 

The result is very cool: a form that can edit an object without the need to write any C# or VB code at all. Coupled with the CSLA .NET ValidationPanel to display validation results, you can create a highly interactive data edit form purely with XAML – and of course a CSLA .NET style business object doing all the work behind the scenes.

These new capabilities will appear in CSLA .NET 3.0 Beta 2 - hopefully later this week.

Wednesday, June 20, 2007 10:14:03 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [1]  | 

I’ve been spending some quality time with WPF and Visual Studio 2008 Beta 1 (Orcas) over the past few months. A couple observations I’ve made:

Observation ichi:

Putting code in a Page/Window constructor is bad. Yes, I know it is the “C# way”, but it is bad. The “VB way” of putting code in the Loaded event handler is better.

Why?

Because any exceptions thrown in the constructor prevent the page/window from loading at all, and you have to catch those exceptions in the code that is creating the page/window. In many navigation scenarios you can’t catch them, so the user gets an ugly WPF exception dialog.

However, if you do all your init work in the Loaded event handler, the page/window instance already exists. Navigation has already happened, so the “calling code” is no longer responsible for your page/window going haywire. Instead, you can actually handle the exception and show a nice dialog, explaining to the user what happened, and you can (if desired) navigate somewhere else or whatever.

Observation ni:

Handing control events with += or AddHandler is superior to using WithEvents/Handles. Yes, I am a strong advocate of WithEvents/Handles, and it is one of the major missing features in C#, but for WPF it turns out to be a negative.

Why?

Because the Handles clause links the name of the control to the code behind. The AddHandler or += approach, while less attractive in many ways, only couples the event name to the code behind.

In other words, when using Handles you get code like:

Private Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs) _
  Handles Button1.Click

While the AddHandler approach results in this code:

Private Sub SaveData(ByVal sender As Object, ByVal e As EventArgs)

The value of the second approach is that any control can route an event to SaveData(). It doesn’t have to be a button, much less Button1. It actually doesn’t even have to be a Click event. It could be almost any event.

The result is that the Presentation (XAML) is less coupled to the UI (VB/C# code) this way than when using Handles.

Unfortunately the Handles approach is more explicit and thus more readable (which is why C# should really get the Handles feature), so we’re left trading readability in order to gain loose coupling…

WPF
Wednesday, June 20, 2007 9:51:35 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [7]  |