in
Forums
Blogs
DevExpress.com
Client Center
Support Center
DevExpress Channel

Gary's Blog

  • XAF – Distributed Pair Programming and Fast Prototyping

    Using XAF recently reminded me of my Smalltalk days in the early ‘90s, more on why that was at the end of the post, but for now let’s talk about pair programming. You know about pair programming right? It’s a practice in eXtreme Programming whereby two programmers sit at the same keyboard and work on the same programming task. One concentrates on the strategic purpose of the task, the other (normally the ‘driver’) concentrates on the tactical aspects of getting the task done. Working this way, the theory goes, both together can be more productive than two programmers working separately and, to be fair, this is generally true.

    I’ve been involved with agile since back in the mid ‘90s when I worked with DSDM at IBM and I’ve tried most agile practices, some I like and they work for me others, not so much. With paired programming however I’ve always managed to get the sort of productivity gains that have been advertised, I guess I’m just one of those types who works better collaboratively.  There is one area however, where paired programming can be a bit of a PITA and that is if the guy playing the “strategic role” can’t keep his mitts off of the “tactical role”, those are fun days.

    The solution for this, I’ve found, is to pair with a subject matter expert. They have no problem keeping their mind fixed on the strategic goals, as it’s all they know, and they are happy to let you bash away on the keyboard and handle all the “tedious” tactical stuff. Okay, now I know that this is not the way paired programming is supposed to work and I know that doing this will mean that I lose some of the benefits of pairing, but it works for me and it gets the job done; which, at the end of the day, is what the Agile Manifesto is all about, right?

    So, in general, that’s worked well for me in the past, back when I had a proper job cutting code. Now of course, I’m an evangelist for an American company and I work from home on the banks of the Tay in Scotland. How can I pair program now? Well, as it happens, there are tools that will help you do that if distributed paired programming is your thing. I found this out earlier this week when I had a conversation that went something like this…

    Her: This sucks!
    Me: Something in particular, or just everything in general?
    Her: We have this information and it’s all locked up in places I don’t need it to be and that sucks!
    Me: (Knowing what’s coming) Yeah, that certainly sounds sucky.
    Her: What I really need is an app to handle all this…
    Me: (Wincing) Hmmm…
    Her: How long would it take you to work your XAF magic on this problem?
    Me: Longer than I have to spend on it.
    Her: Oh puuuleeeeeeeese! Besides, coding stuff is fun, you know it is.
    Me: (damn she found my week spot) Okay, let’s do it!

    Now as we don’t work together in an office “doing it” is a little more complex than her just moving her chair over to my desk, but there are tools that help. So we got on Skype so we could talk, and we started up SharedView so she could see my desktop and I fired up XAF so we could hack away and in under an hour we had a working prototype of an app that solved her problem.

    So what’s my point? Twofold really, firstly, just because you are not co-located does not mean that you can’t work in an agile manor. Secondly, XAF is a cracking prototyping tool! So if you have XAF, even if you have no intention of using it to build your finished product for whatever reason, don’t forget that you can use it to build a prototype, in real time, whilst you sit down with your subject matter expert.

    A fact, that brings us full circle. Remember I said, at the top of this post, that I’d been reminded of my Smalltalk days when using XAF? Well this is why. One of the first jobs I had as a Smalltalker was in a C++ shop, prototyping work that was to be carried out by the C++ devs? Why? well because with Smalltalk we calculated that I could get code up and running in around a fifth of the time that they could. You can get similar productivity gains by using XAF, so why not check it out?

  • XAF – Project Management Application

    Recently I had an IM chat with the XAF team that went something like this (I paraphrase of course):

    Them: Hey Gary we need a new PM app so we’re gonna write one and we want you to blog about it as we go.
    Me: Cool, no problem. Just let me know what you want and I’ll get it out there on the blog.
    Them: That’s great. Thanks. You know you’re the best evangelist we’ve got, right?
    Me: yeah I do.
    Them: The thing is…
    Me: Yeeeeees?
    Them: We’re kinda busy with the whole Writing-XAF-Thing, so maybe you could write the app and we’d be your customers; it’d be done agile like?
    Me: You mean you’d change your mind at every turn?
    Them: Yeah.
    Me: And whilst this is going on, you want me to blog about it so our customers can throw in their tuppence worth too?
    Them: Yeah oh, and can you ship the code too so that they can use it for reference?  
    Me: By ‘reference’ you mean pick apart every line of my code and hold it up for scrutiny and public ridicule?
    Them: Yeah, sucks to be you, huh?

    imageAnd so our XAF Planning Application was born. Now I know what you are thinking (even you Rory Becker and frankly that’s disgusting). You’re thinking here’s another XAF RWA. Well you’re wrong, it’s not. We’ve spoken before about the fact that we’re not doing a RWA for XAF, not now, not ever, no siree Bob. What this is, is an application that will be used in the real world, and that, dear reader, is completely different. :-)

    This application is going to be used by the XAF team for planning projects, and umm… holidays and gadget buying trips and… well you get the idea, and it works something like this. Well, it works something like this for this iteration, I dare say there’ll be changes prompted by the team (and you guys) for iteration 2 – N, but for now, it works like this:

    When you open the application you will notice that there are two groups. The first group, labelled “Project” holds an action for Project and one for Estimate. The first will allow you to work with Projects whilst the other will allow you to work with Estimates. Projects are pretty self explanatory and Estimates will allow you to “size” a project at the “getting the budget” phase, before there’s even is a project to speak of. (Of course, being the first iteration that functionality is not complete, but we can CRUD Estimates in the meantime). Once the project has been given the go ahead, Tasks can be created from these Estimates, or they can be created manually.

    Okay so let’s have a closer look at Estimates:

    image

    As you can see, an Estimate has a name, a summary of the work to be done, the effort required to complete the task (in days) and, optionally, the Resource who will carry out / test / manage the Task.

    Now let’s have a look at the Project:

    image

    Our Project has name, a manager (the person we’ll all blame when it goes wrong), the percentage complete (this will be calculated from the percentage completes of the tasks attached to this project), a start date and an end date. The Project also has collections of Estimates, Tasks, Resources and Milestones for the Project.

    In the second group there are actions for Project Manager and for Resource. Currently anybody working on the Project who is not a Project Manager is just a Resource, this may change in the future. Resource inherits from the built in Person class within XAF and Project Manager inherits from Resource.

    As this is the first iteration I have not included the source code as it only contains the class definitions and validation rules and, as anyone who works with XAF will tell you, that is not very exciting. Having said that, if anyone desperately wants the code from this iteration just leave a comment here and I’ll publish it.

    Well that is it for this post. I’m planning weekly iterations and in next week’s iteration we’ll look at creating Estimates and then adding those to a newly created Project, before using them to automatically generate Tasks for the new Project.

  • What’s new in the iPhone OS 3.0?

    So June 17 finally rolled round and I was able to update my iPhone from 2.X to 3.0, yay! Of course it wasn’t that straight forward, when is it ever, right? I mean the download went smoothly enough, but then I had to wait for the Apple Activation Server, and wait, and wait, and wait… Finally, everyone else stopped getting their activation and I managed to get mine through. So having done that, what’s new…?

    Well for a kick off, they’ve finally fixed my two bug bears with the iPhone:

    MMS

    Finally, we have MMS, yes that’s right iPhone users, welcome to the ‘90s we, at last can send and receive picture messages! I mean we always could before, sort of, but it was a real pain. Firstly, if someone sent you a picture then you got a text from your provider telling that you had a picture and giving you a url to go to. Then you had to open Safari and head over there and then type in your phone number plus a passcode and then you could finally see the picture. Phew, what a lot of needless effort!

    Now it’s much better, now the pictures appear, inline, in your text conversations (as shown) and you can double tap to open them to full size if you wish, all seamlessly. Yay, about time Apple!

    Talking of text messages, that brings me nicely on to the second bug bear of mine that Apple have fixed with this release and that’s the fact that you couldn’t delete single messages in a text conversation. You had to delete the whole conversation or nothing. How dumb was that? Happily that is fixed now and you can delete individual messages.

    Speaking of ‘90s usability, Apple have also giving us iPhone users the ability to forward messages too. So the next time somebody sends you a joke by text, you’ll be able to pass it on, instead of just having to remember it for the next time you are with your mates in the pub, by which time of course, they’ve all already heard it as they got the original text forwarded to them! :-)

    Rounding off our trip back to the ‘90s with the iPhone we now have, the long awaited (at least by me), copy cut and paste functionality. Why that wasn’t there from the get go, I’ll never know.

    But this release is not all about playing catch up with functionality, there are several new features. There’s what I call Etch-a-Sketch functionality. If you are typing away in an email or something and you make a mistake, then just shake the iPhone and it’ll pop up a dialog box asking you if you want to undo the typing.

    Also Apple have beefed up the iPhone’s search features in two way. Firstly it is enhanced in applications like mail etc, but also there is a new “Spotlight” feature which can be accessed by swiping left from the home screen or by pressing the home button when on that screen.

    More Etch-a-Sketch functionality can be found in the iPhone’s iPod player. Simply shake the iPhone to enter shuffle mode; though Apple may have this set a little to sensitively as there are reports on the Net of iPhones shuffling during particularly bumpy flights, or when running to cross the road. If this happens to you, never fear, you can turn this functionality off under Settings –> iPod. Staying with the iPod functionality for a moment longer, there is now the ability to playback video in either landscape or portrait modes you can also jump back exactly 30 seconds and play at either half or double speed.

    The 3.0 release also come with parental controls, but we don’t really care about that do we? I mean, let’s face it, our kids are not going to get their grubby little hands on our lovely shiny iPhone now are they?

    Well this has been a short tour around some of my favourite functionality in 3.0, it’s by no means complete, but I hope you’ve enjoyed it. For a more complete run down you might want to check out the Apple site for more details.

  • XAF and the Secret Validation Information

    Ever seen the XAF validation dialog?

    image

    Yeah of course you have. Ever double clicked on the text in the “Description” column? Nope, me neither until recently, try it now:

    image

    Whoah, what happened there?! DevExpress secret sauce happened! Well okay, not so secret now I’ve told you. What it is, is a dialog that will give you all kinds of handy information about the validation that was just executed. Information that will help you if your validation isn’t working just how you think it should.

    Pretty cool eh? Right, I’m off before the XAF team finds out I’ve spilled the beans. :-)

  • XAF – RuleCriteria and Read Only Properties

    As a man I never read the instructions; it’s baked into our DNA. There were no instruction manuals back when we lived in caves, right? So if we didn’t need them then, we sure as heck don’t need them now. This applies doubly so when I’m working with XAF. Why? Two reason really. Firstly, it allows me to see how intuitive XAF is – does it work, out of the box, the way I naturally think it should? Secondly, when I get stuck, it allows me to see how easy it is to get unstuck using our documentation. (okay when I said I never read instructions, I meant never *before* the fact.)

    Right now I’m working on an XAF application (more on that later) and I want to set up some validation rules; specifically I want to validate that a StartDate is greater than or equal to today’s date. So, naturally, I intuitively I write:

    [RuleCriteria("StartDateMustBeAfterToday", DefaultContexts.Save, "StartDate >= DateTime.Now.Date")]

    Which doesn’t work and throws this error:

    image

    Well okay, so much for intuition, time to find out how it should really be done. So, I open the documentation page for RuleCriteria and I read it; and it’s right there, you saw it didn’t you? No? Meh, me neither first time round. It’s there in the “Remarks” section.

    “In criteria, you can use Read-Only Parameters. For instance, the "Today = '@CurrentDate'" criterion means that the Today property must be set to the current date.”

    That single sentence, tucked away in the remarks section is important, hence my post today. It means two things. One, that my code should have be written as:

    [RuleCriteria("StartDateMustBeAfterToday", DefaultContexts.Save, "StartDate >= '@CurrentDate'")]

    Which will throw the following validation error, as required:

    image

    It also means that all the read-only parameters, which we document as being used for filtering (which is true) can also be used in RuleCriteria, so go check them out and have fun!

  • It Don’t Mean a Thing if it Ain’t got that Bing!

    Unless you’ve been hiding somewhere not even the search engines can find you, you couldn’t help but notice that there’s a new kid on the block; that new kid comes in the shape of Bing, Microsoft’s new search engine. So new in fact that it’s still in beta; but then again, every web app’s in beta these days, right?

    So what’s Bing all about? Well the first thing you need to know is that it’s not a search engine, oh no; it is, in fact a “decision engine”. Microsoft say,

    “Bing is specifically designed to build on the benefits of today's search engines but begins to move beyond this experience with a new approach to user experience and intuitive tools to help customers make better decisions, focusing initially on four key vertical areas: making a purchase decision, planning a trip, researching a health condition or finding a local business”

    Leaving aside that somewhat freaky “vertical area” of “researching a health condition” – cos frankly that’s what the doctor’s for, right – is Bing successful at the others? Well, let’s find out. Firstly, making a purchase. Now, a certain young lady who works for DevExpress has been banging on about getting a Dell Mini since she was at TechEd, how does Bing stack up against Google in helping her make her “decision”? Let’s check it out by typing “Buy Dell Mini” into each engine, Google first…

    image

    As you can see (click on the thumbnail for a bigger image), with Google you get sponsored links, then shopping links, then the Dell site. Not too bad and now Bing…

    image

    Here, it’s sponsored links, followed by the link to the Dell site. So more or less a draw then. The only difference really is that Google shows the site map of the Dell site, which is more helpful if you were looking for a particular page on the site.

    How about planning a trip? Let’s go to the Lake District, first let’s fly Google…

    image

    Google has sponsored links and then straight in to the travel and accommodation links. Let’s see what Bing gives us…

    image

    Well it gives us sponsored links followed by a map of the local area and links to some local hotels. Much more useful in my opinion.

    Lastly, let’s try out finding local business. After all this searching I think I need something to eat, and we all know you can’t go wrong with a good curry. Let’s see what Google can offer us…

    image

    Google offers a map of the local area and a list of restaurants on the map. Very impressive. Let’s see how Bing shapes up…

    image

    Meh, not so good. Just the usual sponsored links and then the links to the local restaurants, but not the helpful map and links that Google provided or indeed, which Bing provided for the travel search.

    Well, after this rather rudimentary search, I’d say Bing still has a way to go to push Google off the top spot but then, as Steve Ballmer himself said, it’s going to take Microsoft years and years to get anywhere in search. The big question now is, is Bing the second best search engine out there?

  • Google – The Next Wave

    One of the trends to catch my eye this week is Google Wave; the personal communication and collaboration tool, was announced at the Google I/O conference, which ran from May 27 –28 this year.

    Wave is an open source platform (built entirely using Google Web toolkit) and showcases what can be done in the browser. The entire platform is an HTML5 application, with the exception of adding attachments to a Wave, for this alone you need Google Gears. The platform has been under development for the last two year at Google and is brought to you by the same team that built Google Maps. Google Wave has an API, which will allow you to embed Wave in your own web pages (your blog for example) or create extensions to the platform. As I said, Wave is open source and there is a published protocol so that anyone can create their own Wave system.

    So, how does it work? Well take email for example, which was invented 40 years ago and was modelled on a well understood messaging protocol; snail mail. Messages were sent to one or more people and each recipient would reply, or not, as need be. Now, imagine if we were to invent email today with all the experience we have with bulletin boards and wikis etc. there is no doubt that it would look quite different. Wave is Google’s idea of what email would look like if it were invented (by them) today. Instead of a number of reply –> response pairs, which is the current email model, Wave sees the entire conversation as a single conversation object (living on a server) that can be opened and edited by anyone added to the Wave. This metaphor allows a participant in the Wave to instruct the server to insert his reply inline, including his avatar, so that it is clear who is saying what. Once there has been any number of such edits, and if it is required, the “finished” document can be extracted from one Wave into a new Wave for wider circulation. But what happens if you are added to the Wave late and you want to see how the present state of the document was reached? Well for that there is the playback function which allows you to see how the document evolved, from it’s inception, to it’s present state – one edit at a time. Google are planning to add a set of power tools to this functionality that will allow you to only playback edits from a single participant etc. Of course, there is also an option to make your edits visible to only a subset of the participants.

    Powerful though this undoubtedly is, the real collaborative power comes from Wave’s ability to be embedded in other web pages such as blogs; this opens the blog up to the full power of Wave. Now when your readers comment on a posting they get added as a participant of that Wave. You can reply to them from your web page, or from the Wave client (a browser application). From your client you can add others to the Wave, who can contribute without ever going to your web page, as any replies made by them are visible anywhere that Wave is visible, including your web page. As other readers comment on these replies, so they are added to the Wave as participants and join the conversation. After some time, it maybe be that no one is updating the Wave from your web site, but are instead using the Wave client to continue the conversation, but the beauty of Wave means that the full conversation is still visible on your page.

    The API is not limited to embedding Wave in other web pages though, it also allows you to create extensions to Wave. The team realised how important developers were to the success of Wave so they wanted to make sure that the extension model was robust. To do this they wrote a lot of the functionality of Wave in that very extension model so that their (and your) extensions would live as first class citizens of the Wave platform. One such extension is the spell checker; the Wave spell checker not only checks the spelling of words (as you’d expect) but is context sensitive, being able to correctly detect not only misspellings but the incorrect use of a correctly spelt word that sounds the same; e.g. through and threw, been and bean, won and one, etc.

    There is no doubt in my mind that Google Wave is going to be a great boon to those of us in the evangelism world who use collaborative tools day in, day out, and I can’t wait for it to ship later this year.

  • DevExpress and the Agile Manifesto

    Recently I attended the Agile Edge conference in London, where I presented a talk entitled “Compare and Contrast the Implementation of Agile methods in the Enterprise and ISVs”, sound thrilling or what? Actually, it is an interesting talk (well my audience thought so anyway) but it begs the question “What does DevExpress have to do with agile development”?

    Well, as it happens, there are two principles of the Agile Manifesto, where DevExpress can support the agile team. The first of those is

    “Continuous attention to technical excellence and good design enhances agility.”

    image DevExpress helps the agile team achieve this principle with our CodeRush product. The new code analysis feature in the 9.X version help developers maintain “technical excellence and good design”. With this feature of CodeRush enabled the tool will mark (in the right hand gutter) the line in the source code where it thinks the developer has deviated from best practice. When the developer then highlights the mark, CodeRush will provide a call out detailing errors in the developer’s code (as shown in the image to the left). This will allow the developer to systematically work his way down the list of results from the analysis until all the results have been fixed, or the developer is satisfied that they can safely be ignored.

    Of course, this feature requires the use of background compilation and as such may slow down your environment (although I have to say it doesn’t on my Thinkpad Z61p with 3Gb of RAM). If you find that this is the case, then the feature can be turned on and off, as required, by clicking the appropriate button in the toolbar.

    The other principle where DevExpress can help the agile team is

    “Simplicity--the art of maximizing the amount of work not done--is essential.”

    It’s much easier to see how DevExpress can help the agile team with this principle. Our large array of components for Windows, web, WPF and Silverlight cuts down, drastically, the amount of work that a team of developers has to do. If your team is handed the task of developing a new accountancy suite for your enterprise, you do not want to be spending three months developing your own charting solution, for example. No, you want to buy in a really solid third party solution - in other words, you want to “maximize the amount of work not done”.

    So, as you can see, although it may not appear at first glance that a company like DevExpress has a lot to offer the agile team, if you scratch beneath the surface you will see that we have tools and components that will help you achieve the principles of the Agile Manifesto.

    Digg This
  • XAF at TechEd – Day One

    And we’re off! And off to a good start too with DevExpress scooping 11 awards. It was also a successful day on the XAF kiosk. Our competition is drawing the crowds and we’re run off our feet demonstrating our framework products.

    The highlight of the for first day, for us XAF guys, had to be the SQL Server admin that I spoke to (there are IT Pro guys here too) who thought XAF solved the problem that the dev team at his company had, so well that he went off and found the devs and dragged them round to the stand to watch the demo. They agreed that XAF was a perfect fit and so went off to find some WIFI so that they could download the trial version. Talking about evangelism firing enthusiasm! :-)

    Of course, not everyone I demonstrated XAF too was quite that enthusiastic but everyone agreed that the idea of a framework, which lifts the boilerplate tasks (security, scaffolding, etc) off of the shoulders of the developer and allows him to concentrate on solving the problems of his particular enterprise, is a very good thing indeed. With such enthusiasm from XAF from day one, I can’t wait to get started on day two.

    Of course it’s not all work and no play; here at DevExpress we are really good at making friends, so if you happen to be at TechEd then stop by the DevExpress booth and say hi; see for yourself how cool our developer components, tools and frameworks are.

  • Follow me and I will make you Fishers of Men

    Surely, if there were a professional body for evangelists, this would be their motto, because that’s what we do as evangelists, we gather together like minded people and introduce them to the great new technology that we have found. That is why evangelism is important to us at DevExpress, but I’m writing about it here because it’s important to you too. That’s right, it’s important to the customers of DevExpress too. Why? Well you use our tools to create great products; once you’ve done that you have to sell those products, evangelism is one of the tools at your disposal to do that; and yes it’s even important to you, yes you, that guy at the back reading email on his iPhone instead of listening to me. Just because you work in the enterprise and don’t actually sell your product to the public, doesn’t mean you don’t have to “sell” your product; where do you think the funding for your project came from? Yeah, that’s right, internal stakeholders and you better believe you have to “sell” them on the benefits of it.

    Over here I wrote a blog post about the channels available to you, our customers, through which you can contact us. However, that is only half the story. For some reason, there will always be the customers who prefer to make their comments known via their blog or by other such means. Because of the fact that they don’t channel that comment to us, there is a danger that we may never become aware of their issues. That is where the comment at the top of this post comes in. It is up to us, as evangelists, to trawl (or fish for) those comments; and in this post we’ll look at some of the ways of doing this.


    image Firstly, and most obviously perhaps, there the general Internet search. By clicking the advanced search link on the Google homepage you can configure your search to enable you to drill down to some fairly specific information. The advanced search will let you filter on: the text of your search, either including or excluding specific words or phrases; the domain, only searching particular web sites; the date, narrowing the search to a specific time period; by usage rights, filtering the search to a specific license and you can also specify where on the page your search criteria shows up.

    Next there is the, slightly more specific blog search from Google. This search will allow you to search for your product within blogs, instead of the Internet as a whole.

    Sticking with Google for the time being, there is also the very powerful Google Alerts which will allow you to search for your products, either within news, blogs, videos, groups, are comprehensively (which is all of the above). Google will then collate the results for you and email them to your inbox; either as it happens, once a day or once a week.

    Of course there are more specific places were your customers may hang out, Twitter for example. Twitter is a “microblogging” service where you, or your customers, can post micro blog posts (of 140 characters or less) on what ever topic they like. Hopefully, your product. Now, Twitter also offers a search service and you can use this service to search those micro posts for mentions of your products. Of course, the great thing about Twitter is that if you do find a post mentioning your product, you can reach out to the author, by preceeding your comment with the “@” symbol and their name, thus giving you a level of feedback that you don’t have (necessarily) with other blogging tools.

    Well those are some of my favourite tools to make me a “fisher of men”. But of course, my readers are far smarter than me. So what’re your favourite tools / techniques, leave them here in the comments.

    Digg This
  • Community Resource for CodeRush Plugins

    Are you interested in creating CodeRush plugins? If so then Rory Becker (a valued member of the DevExpress community) has put together a great resource showing you how to get started. Check it out here.

    Digg This
  • Come and see (the new) CodeRush and RefactorPro! in Belfast!

    This Friday I’m heading across the Irish Sea for the DDD Belfast conference, where I’ll be speaking on the subject of refactoring. The event itself will be held on Saturday April 4th, when some 250 attendees will make their way to the Belfast Metropolitan College in order to hear speakers deliver great talks on a wide range of subjects.

    As always, I’d love to meet up and chat with anyone from the DevExpress community who’ll be attending the event; so don’t be shy, come and say hello – I don’t bite, honest. :-)

    Can’t make it to the event? Don’t worry, I know Saturdays are “family time” and that means that some of you can’t attend such events; but just for you, I’ll be blogging and live Twittering from Belfast so you wont miss a thing! Just follow me on @GaryShort and tune into the #DDDBelfast and #DXInBelfast tags.

    While you are doing that, of course, don’t forget to hop across to the ASP.Net site and vote for your favourite DevExpress tool or component.

    Okay, that’s all for now, I’ve got a presentation to write after all… See you in Belfast!

    Digg This
  • Using XAF to Build Windows MDI Applications

    This blog post will demonstrate how to use XAF, along with DXperience controls, to create an MDI application, the image below shows what the finished application will look like:

    As you can see from the image, the child forms are represented by tabs within the main form. However, you will be able to customize the location and appearance of the child forms via the XtraTabbedMdiManager component. You can read more on the XtraTabbedMdiManager class in the documentation.

    There are 7 short steps to creating this MDI application and they are as follows:

    Step 1 - Create a new XAF Windows solution and give it a name (MDIDemo):

     

     

    Step 2 - Create the MDIMainForm And MDIChildForm Templates

    To build an MDI application, you should develop two Frame Templates:

    • MDIMainForm - a Frame Template for the Main Window (the Window that is first displayed when starting an application);
    • MDIChildForm - a Frame Template for child Windows (all the Windows except the Main Window).

    You won't have to create these Templates from scratch. The eXpressApp Framework installation provides the sources of the main Templates. You can use the MainForm and DetailViewForm Templates as prototypes for your new Templates:

    • In the Solution Explorer, create a new folder called "Templates" within the MDIDemo.Win application project.
    • Invoke the context menu for the new "Templates" folder and select the Add | Existing Item... menu item. In the invoked dialog, navigate to the [ProgramFilesFolder]\Developer Express Inc\eXpressApp Framework\Sources\FrameTemplates\ folder. Select the MainForm.cs and DetailViewForm.cs files from the "CS" folder if your project is in C#, or the MainForm.vb and DetailViewForm.vb files from the "VB" folder if your project is in Visual Basic. Press the Add button. Visual Studio will create local copies of these two files.
    • Rename the added MainForm.cs (MainForm.vb) file to MDIMainForm.cs (MDIMainForm.vb), and the DetailViewForm.cs (DetailViewForm.vb) file to MDIChildForm.cs (MDIChildForms.vb). Rename the MainForm and DetailViewForm classes and all the references to them inside these files in the following manner:
      MainForm to MDIMainForm and DetailViewForm to MDIChildForm.

    Then, you should modify the MDIMainForm Template as defined below. The MDIChildForm Template doesn't need to be modified.

    Step 3 - Modify the MDIMainForm Template

    You have to make some changes in the MDIMainForm Template. For this purpose, open the MDIMainForm file in the Visual Studio Form Designer. There, do the following:

    • Via the Properties window, set the MainForm's IsMdiContainer property to true.
    • Remove the viewSitePanel from the form. Since this form is just a container for child forms, it must not contain Views. In the MDIMainForm.cs, modify the Initialize method call in the following manner:
    Initialize(mainBarManager, containers, new IActionContainer[] { cObjectsCreation,
    cRecordEdit, cView, cPrint, cExport }, null, navigation);

    • From the DX: Navigation & Layout page of the Toolbox, drag and drop an XtraTabbedMdiManager component to the form.

    Now, create the menu items that will manage MDI functions:

    • Select the barManager component on the form. This will allow you to perform toolbar design-time customizations.
    • Click the small [Add] link on the MainMenu toolbar (the toolbar at the top, by default).
    • Select the Menu (BarSubItem) item in the invoked context menu. This will create a new toolbar item. Give it the Window name (for instance).
    • Click the new toolbar item twice (two clicks with a short pause in between, not a double click), to expand it. Via the [Add] link inside the invoked menu, add a Button (BarButtonItem) toolbar item. Set the new item's name to, for instance, Close All Windows .
    • Select the Close All Windows toolbar item, and add an ItemClick event handler via the Properties window. In this event handler, implement the code that closes all open child Windows, as shown below:

    private void barButtonItemCloseAll_ItemClick(object sender, ItemClickEventArgs e) {
    foreach(Form child in this.MdiChildren) {
      child.Close();
      if(child.Visible)
         break;
    }
    • Using the same technique as above, add an MDI children list (BarMdiChildrenListItem) item to the Window toolbar item. This is a special item type, which will be populated with open child Windows automatically. It will also allow navigating to the selected Window.

    A child form will be shown as a tab within the main form. Both the main and child forms will have their own toolbars. This will look unattractive because of the nested MainMenu toolbars inside each tab. So, you should merge the items of the main and child MainMenu toolbars. The BarManager does this automatically, but you should hide a child Window's MainMenu toolbar in code. For this purpose, add a handler to the barManager's Merge event, via the Properties window:

    using DevExpress.XtraBars;
    //...
    private void barManager_Merge(object sender, DevExpress.XtraBars.BarManagerMergeEventArgs e) {
        foreach (Bar childBar in e.ChildManager.Bars) {
          if (childBar == e.ChildManager.MainMenu || childBar == e.ChildManager.StatusBar)
             continue;
          childBar.Visible = false;
        }
    }

    Step 4 - Add the Filters Action Container to the Detail View Form Template

    There are Actions that are enabled when there is a View on the current frame. The MDIMainForm Template doesn't contain a View. So, the Actions that are mapped to the Action Containers contained in this Template are displayed disabled. For instance, the FilterController.SetFilterAction is displayed by the Filters Action Container contained in the MDIMainForm Template. You can make this Action and other similar Actions available, if you add the Filters Action Container and other required Action Containers to the MDIChildForm Template. This Template's Action Containers are displayed in the main form, because of the merge operation performed under the main and detail form's Action Containers (see above).

    The code below demonstrates the code snippets that you should add to the MDIChildForm.Designer.cs (MDIChildForm.Designer.vb) and MDIChildForm.cs (MDIChildForm.vb) files, to add the Filters Action Container:

    In the MDIChildForm.Designer.cs (MDIChildForm.Designer.vb) file:

    using DevExpress.ExpressApp.Utils;
    
    //...
    
    partial class MDIChildForm {
       private void InitializeComponent() {
       //...
       this.cFilters = new DevExpress.ExpressApp.Win.Templates.ActionContainers.ActionContainerBarItem();
       //...   
       // 
       // mainBarManager
       // 
       //...
       this.barManager.Items.AddRange(new DevExpress.XtraBars.BarItem[] {
          //...
          this.cFilters,
          //...
          });
       // 
       // barSubItemEdit
       // 
       this.barSubItemEdit.LinksPersistInfo.AddRange(new DevExpress.XtraBars.LinkPersistInfo[] {
          //...
          new DevExpress.XtraBars.LinkPersistInfo(this.cFilters, true)
          });
       // 
       // StandardToolBar
       // 
       //...
       this.StandardToolBar.LinksPersistInfo.AddRange(new DevExpress.XtraBars.LinkPersistInfo[] {
          //...
          new DevExpress.XtraBars.LinkPersistInfo(this.cFilters, true),
          //...
          });
       // 
       // cFilters
       // 
       this.cFilters.Caption = CaptionHelper.GetLocalizedText(FrameTemplatesDetailViewForm, "Filters","Filters");
       this.cFilters.ContainerId = "Filters";
       this.cFilters.Id = 26;
       this.cFilters.MergeType = DevExpress.XtraBars.BarMenuMerge.MergeItems;
       this.cFilters.Name = "cFilters";
       //...
       private DevExpress.ExpressApp.Win.Templates.ActionContainers.ActionContainerBarItem cFilters;
    }

    Step 5 - Replace the Default Templates with the MDIMainForm and MDIChildForm

    By default, an application uses the MainForm and DetailViewForm Templates to display the Main Window and Windows with Detail Views, respectively. You should change this default behavior, and make the application use your MDIMainForm and MDIChildForm Templates instead. For this purpose, open the Program.cs file, and add a handler to the XafApplication.CreateCustomTemplate. This event is raised each time a Template is required.

    static class Program {
        static void Main() {
            MDIDemoWindowsFormsApplication application = new MDIDemoWindowsFormsApplication();
            application.CreateCustomTemplate +=
               new EventHandler<CreateCustomTemplateEventArgs>(application_CreateCustomTemplate);
            // ...
        }
    }

    Implement the CreateCustomTemplate event handler, as shown below:

    using DevExpress.ExpressApp.Win.CustomTemplates;
    //...
    static void application_CreateCustomTemplate(object sender, CreateCustomTemplateEventArgs e) {
       if(e.Context == TemplateContext.ApplicationWindow) {
          e.Template = new MDIMainForm();
       } else
       if(e.Context == TemplateContext.View) {
          e.Template = new MDIChildForm();
       } else {
          e.Template = null;
       }
    }

    Step 6 - Implement the MDIStrategy

    A Show View Strategy is a special abstraction which determines how and where to show Views (see ShowViewStrategyBase). The eXpressApp Framework comes with two Windows Forms Show View Strategies:

    • ShowInSingleWindowStrategy
      Using this strategy, child windows are displayed within the Main Window.
    • ShowInMultipleWindowsStrategy
      Using this strategy, child windows are displayed individually.

    In your MDI application, you should implement a new strategy by inheriting from the ShowViewStrategy class:

    using DevExpress.ExpressApp.Win;
    using System.Collections.Generic;
    using DevExpress.ExpressApp;
    //...
    class MDIStrategy : DevExpress.ExpressApp.Win.WinShowViewStrategyBase {
        private List<WinWindow> delayedToShow = new List<WinWindow>();
        private List<WinWindow> childWindows = new List<WinWindow>();
        private void window_Closing(object sender, System.ComponentModel.CancelEventArgs e) {
            e.Cancel = true;
        }
        private void window_Closed(object sender, EventArgs e) {
            WinWindow window = sender as WinWindow;
            window.Closing -= new System.ComponentModel.CancelEventHandler(window_Closing);
            window.Closed -= new EventHandler(window_Closed);
            childWindows.Remove(window);
        }
        private void Form_FormClosing(object sender, System.Windows.Forms.FormClosingEventArgs e) {
            Form form = sender as Form;
            WinWindow window = FindChildWindowByForm(form);
            e.Cancel = false;
            if (e.CloseReason == System.Windows.Forms.CloseReason.MdiFormClosing) {
                if (window.Form.MdiParent.MdiChildren[0] == window.Form) {
                    e.Cancel = !CanCloseMDIParentWindow();
                }
                if (!e.Cancel) {
                    window.Form.FormClosing -= new FormClosingEventHandler(Form_FormClosing);
                    window.View.SynchronizeInfo();
                    window.View.Close(false);
                }
            }
            else {
                e.Cancel = !window.CanClose();
            }
        }
        private WinWindow FindChildWindowByForm(Form form) {
            foreach (WinWindow window in childWindows) {
                if (window.Form == form) {
                    return window;
                }
            }
            return null;
        }
        private bool CanCloseMDIParentWindow() {
            foreach (WinWindow window in childWindows) {
                if (window.View != null && !window.View.CanClose()) {
                    return false;
                }
            }
            return true;
        }
        protected override void ShowViewFromCommonView(ShowViewParameters parameters,
              ShowViewSource showViewSource) {
            WinWindow existWindow = FindWindowByView(parameters.CreatedView);
            if (existWindow != null) {
                parameters.CreatedView.Dispose();
                parameters.CreatedView = existWindow.View;
                existWindow.Show();
            }
            else {
                ShowViewInNewWindow(showViewSource.SourceFrame,
                   parameters.CreatedView, TemplateContext.View, parameters.Controllers);
            }
        }
        protected override void ShowViewCore(ShowViewParameters parameters,
              ShowViewSource showViewSource) {
            if (parameters.TargetWindow == TargetWindow.Current &&
                  showViewSource.SourceFrame == MainWindow) {
                parameters.TargetWindow = TargetWindow.Default;
            }
            base.ShowViewCore(parameters, showViewSource);
        }
        protected override void ShowViewFromLookupView(ShowViewParameters parameters,
              ShowViewSource showViewSource) {
            ShowInModalWindow(parameters, showViewSource.SourceFrame);
        }
        protected override void BeforeShowWindow(WinWindow window) {
            if (window != MainWindow) {
                if (window.Form.MdiParent != MainWindow.Form) {
                    window.Form.MdiParent = MainWindow.Form;
                    window.Closing += new System.ComponentModel.CancelEventHandler(window_Closing);
                    window.Form.FormClosing += new System.Windows.Forms.FormClosingEventHandler(Form_FormClosing);
                    window.Closed += new EventHandler(window_Closed);
                    childWindows.Add(window);
                }
            }
        }
        public MDIStrategy(XafApplication application) : base(application) { }
        public override void ShowStartupWindow() {
            delayedToShow.Clear();
            try {
                base.ShowStartupWindow();
            }
            finally {
                System.Windows.Forms.Application.DoEvents();
                foreach (WinWindow child in delayedToShow) {
                    ShowWindow(child);
                }
            }
        }
        public override void ShowWindow(WinWindow window) {
            if (!window.IsMain && MainWindow == null) {
                delayedToShow.Add(window);
            }
            else {
                base.ShowWindow(window);
            }
        }
    }

    The MDIStrategy class overrides the following methods to perform the MDI specific functionality:

    • ShowViewFromCommonView

      Called when a View requests another View to be shown (for instance, when the New action is executed within a List View). According to the MDIStrategy, the requested View is shown within a new Window, i.e. a new MDI child form. In addition, if this View is already being shown, a new Window isn't created.

      In a case when a View within a lookup Property Editor or within another View is requested, the ShowViewFromLookupView method is called.

    • ShowViewFromLookupView

      Called when a View in a lookup Property Editor requests another View to be shown. According to the MDIStrategy, the requested View is shown in a modal window.

    • BeforeShowWindow
      Called before showing a Window. Sets the parent form to the current child form.
    • ShowStartUpWindow and ShowWindow
      The ShowStartUpWindow method is called when an application starts. It creates the Main Window, activates its Controllers and calls the ShowWindow method. Some of the activated Controllers can be required to show a child Window by calling the ShowWindow method. Since the Main Window isn't shown yet, problems can occur. To avoid this, the ShowWindow method is overridden. If the Main Window isn't shown, this method adds the Window passed as a parameter to the delayed Window list. The ShowStartUpWindow method shows the Windows from this list after showing the Main Window.

    Step 7 - Replace the Default Strategy with the MDIStrategy

    By default, the WinApplication's Manager uses the ShowInSingleWindowStrategy or ShowInMultipleWindowsStrategy strategy, to show Windows in a UI. You should change this default behavior, and make the Manager use your MDIStrategy instead. To accomplish this, open the Program.cs file and specify the ShowViewStrategy property of the WinApplication's Manager:

    static class Program {
        public static void Main() {
            MDIDemoWindowsFormsApplication application = new MDIDemoWindowsFormsApplication();
            application.ShowViewStrategy = new MDIStrategy(application);
            // ...
        }
    }

    And that’s all there is to creating an MDI application with XAF :-)

    Digg This
  • XAF – Applying HTML Formatting to Windows Forms UI Elements

    XAF uses controls from the XtraEditors suite to build windows forms UI elements. Now, some of these XtraEditor controls allow XAF to format the display text using HTML. So, which of these editors can be formatted using HTML?

    • Static Text Detail View Item's text.
    • Property Editor's captions in Detail Views.
    • Column captions of the Windows Forms GridListEditor.
      By default, XAF uses this List Editor to visualize List Views in Windows Forms applications.

    XAF allows these three elements to be customized via the associated attributes of the Application Model. A complete list of the HTML tags that you can use can be found here. Of course, you can switch the ability to format the display text in this way via the EnableHTMLFormatting attribute of the Application Model's Application | Options node.

    Okay, so let’s have an example or two. Firstly, let’s look at the Static Text Detail View Item's text. Set the Caption attribute of the Application Model's Application | Views | Contact_DetailView | Items | WebPageAddress node to the following value:

    <size=12><color=red><b>Web </b><color=0,255,0><i>Page </i><color=#0000FF><u>Address</u></color></size>

    The following image shows part of the resulting Contact Detail View:

    Now let’s have a look at the column's caption of the default list editor. Set the Caption attribute of the Application Model's Application | Views | Contact_ListView | Columns | LastName node to the following value:

    <size=10><color=#CFCAFF><size=+4>L<color=#B0A8FF><size=+4>A<color=#6F79FF><size=+4>S<color=#4D3EFF><size=+4>T <color=#4D3EFF><size=-4>N<color=#6F79FF><size=-4>A<color=#B0A8FF><size=-4>M<color=#CFCAFF><size=-4>E</color></size>

    The following image shows the resulting Contact List View:

    This is yet another example of how, by leveraging other Developer Express controls, XAF makes you life as a developer easier and you more productive.

    Digg This
  • XAF – Generating Business Classes for Existing Data Tables

    The philosophy of XAF (the 80% case, if you will) is that the framework will be used for the creation of green field projects. Although that is how we expect the framework to be used in the majority of cases, this does not mean that we have forgotten about those developers who are working on applications for which there is already an existing database. In this post, we’ll look at how XAF supports the developer in generating business classes for existing data tables.

    To generate these classes we are going to use the design time wizard; to do this, in the Solution Explorer, select the Add | New Item... context menu option within your common module, that’s the module that is used by both the Windows Forms and ASP.NET application projects:

    Next, select the “Persistent Classes” template from the “Add New Item” dialog, and click on the “Add” button:

    The Wizard will then open and you will be able to configure the connection string to your chosen database.

    Multiple database systems (MS SQL Server, DB2, MySql, Firebird, etc) are supported by the wizard. Use the Provider combo box to select the required database type. Note that the corresponding database provider assembly must be available on your machine, otherwise the wizard will fail. :-)

    Click “Next” and a dialog will open allowing you to select which table and columns are to be included. Note that tables with composite keys are not supported by XPO (the technology used under the hood to support XAF) and so such tables will not be included in the list:

    Click the “Finish” button and the classes will be generated for you:

    [Persistent("Customers")]
    public class Customer : XPLiteObject {
        string fAddress;
        [Size(60)]
        public string Address {
            get { return fAddress; }
            set { SetPropertyValue<string>("Address", ref fAddress, value); }
        }
        //...
        string fCustomerID;
        [Key]
        [Size(5)]
        public string CustomerID {
            get { return fCustomerID; }
            set { SetPropertyValue<string>("CustomerID", ref fCustomerID, value); }
        }
        //...
        public Customer(Session session) : base(session) { }
        public Customer() : base(Session.DefaultSession) { }
        public override void AfterConstruction() { base.AfterConstruction(); }
    }

    Having done this, you’ll need to remember to remove the default constructor, as the default Session is not used to create objects in XAF.

    With the classes generated, there is only one task left to complete. Currently, relationships between tables are not reflected in the auto generated classes. So, you'll have to declare the relationships manually:

    [Persistent("Customers")]
    public class Customer : XPLiteObject {
        [Association("Customer-Orders", typeof(Order)), Aggregated]
        public XPCollection Orders {
            get { return GetCollection("Orders"); }
        }
        string fCustomerID;
        [Key]
        [Size(5)]
        public string CustomerID { }
        //...
        public Customer(Session session) : base(session) { }
        public override void AfterConstruction() { base.AfterConstruction(); }
    }
    [Persistent("Orders")]
    public class Order : XPLiteObject {
        Customer fCustomer;
        [Association("Customer-Orders")]
        public Customer Customer { }
        int fOrderID;
        [Key(true)]
        public int OrderID { }
        public Order(Session session) : base(session) { }
        //...
    }

    The code above demonstrates the One-to-Many relationship between Customer and Order objects. The "One" part of this relationship is represented by the Customer property of the Customer type in the Order class. The "Many" part is represented by the Orders property of the XPCollection type in the Customer class. Both these parts use the Association attribute.

    To enable cascading deletion of the dependent objects (if a customer is deleted all the related orders for that customer are also deleted), you can specify the Aggregated attribute for the corresponding properties (see the Orders collection in the definition of the Customer class above).

    Since the Customer field in the Order table now stores a link to the Customer object, you should populate it by the values that correspond to the values stored in the CustomerID field. For this purpose, you can write the following code in the module's updater:

    public class Updater : ModuleUpdater {
        public override void UpdateDatabaseAfterUpdateSchema() {
            Order orderObject = Session.FindObject<Order>(CriteriaOperator.Parse("Customer is null"));
            while (orderObject != null) {
                if (!string.IsNullOrEmpty(orderObject.CustomerID)) {
                    orderObject.Customer = Session.FindObject<Customer>(new BinaryOperator("CustomerID", orderObject.CustomerID));
                    orderObject.Save();
                }
                orderObject = Session.FindObject<Order>(CriteriaOperator.Parse("Customer is null"));
            }
        }
    }
    As you an see from this post, even although XAF is aimed at the developer in a green field project, we have not forgotten those who are working on applications where the database tables already exist. By leveraging the wizard in XPO, XAF allows you to generate business classes for existing data tables.
    Digg This
More Posts Next page »
Copyright © 1998-2009 Developer Express Inc.
ALL RIGHTS RESERVED