Blogs

Gary's Blog

October 2010 - Posts

  • XPO - Explicit Transactions (Coming in v2010 Vol 2)

         

    Coming in 2010.2 is the new ExplicitUnitOfWork. This class derives from UnitOfWork and allows you to easily use explicit transactions in XPO. The advantage of this is that it works with objects as if they were already stored in the database, meaning it appears – to the developer – as if there is no difference between objects in memory and data in the database. The only downside of this is that the class must be the exclusive owner of the database connection.

    Let’s demonstrate this with an example. First, we will declare a Person class:

    using DevExpress.Xpo;
    
     public class Person: XPLiteObject {
         int oid;
         string name;
         int age;
         
         [Key(true)]
         public int Oid {
             get { return oid; }
             set { SetPropertyValue<int>("Oid", ref oid, value); }
         }
    
         public string Name {
             get { return name; }
             set { SetPropertyValue<string>("Name", ref name, value); }
         }
    
         public int Age {
             get { return age; }
             set { SetPropertyValue<int>("Age", ref age, value); }
         }
    
         public Person(Session session)
                    : base(session) {
         }
     }

    And then make a few tests with the ExplicitUnitOfWork:

    using System;
    using DevExpress.Xpo;
    using DevExpress.Xpo.DB;
    using DevExpress.Data.Filtering;
    
    CriteriaOperator criteria;
    
    //Assume the database is empty
    
    using(ExplicitUnitOfWork euow = new ExplicitUnitOfWork(dataLayer)) {
        Person person = new Person(euow);
        person.Name = "Thomas Brown";
        person.Age = 34;
    
        //Try to load from the database object with the same name and the age of
        criteria = CriteriaOperator.Parse("Name = ? AND Age = ?", person.Name, person.Age);
        Person personFromDB = euow.FindObject<Person>(criteria);
    
        //Check that the database loaded the newly created object
        System.Diagnostics.Debug.Assert(ReferenceEquals(person, personFromDB));
        System.Diagnostics.Debug.Assert(person.Oid == personFromDB.Oid);
    }
    
    using(ExplicitUnitOfWork euow = new ExplicitUnitOfWork(dataLayer)) {
        //Try again to load the object from the DB
        Person personFromDB = euow.FindObject<Person>(criteria);
    
        //At this time the object is not loaded, because the changes we do not save
        System.Diagnostics.Debug.Assert(ReferenceEquals(personFromDB, null));
    }

    Note, all of the above applies to objects loaded via XPCollection and XPView.

    So, how does this work? Well, the trick is that ExplicitUnitOfWork opens an explicit transaction when modifying or creating any object. When loading, it saves all of the changes to the database so that it contains the modified objects. When the CommitChanges method is called, the ExplicitUnitOfWork saves the last modification and closes the explicit transaction. After that, all the changes are visible to the entire database.

    Let’s modify our previous example:

    using DevExpress.Xpo;
    using DevExpress.Xpo.DB;
    using DevExpress.Data.Filtering;
    
    CriteriaOperator criteria;
    int personOid;
    
    using(ExplicitUnitOfWork euow = new ExplicitUnitOfWork(dataLayer)) {
        Person person = new Person(euow);
        person.Name = "Thomas Brown";
        person.Age = 34;
    
        criteria = CriteriaOperator.Parse("Name = ? AND Age = ?", person.Name, person.Age);
        Person personFromDB = euow.FindObject<Person>(criteria);
    
        System.Diagnostics.Debug.Assert(person.Oid == personFromDB.Oid);
        System.Diagnostics.Debug.Assert(ReferenceEquals(person, personFromDB));
    
        //Remember the OID of the object
        personOid = person.Oid;
    
        //This time will commit changes
        euow.CommitChanges();
    }
    
    using(ExplicitUnitOfWork euow = new ExplicitUnitOfWork(dataLayer)) {
        //Try again to load the object from the DB
        Person personFromDB = euow.FindObject<Person>(criteria);
    
        //Object loaded...
        System.Diagnostics.Debug.Assert(!ReferenceEquals(personFromDB, null));
    
        //...and the object of one buyout, we retain
        System.Diagnostics.Debug.Assert(personFromDB.Oid == personOid);
    }

    Now let’s think of a scenario, in which the ExplicitUnitOfWork may come in handy. Suppose there are fields, which have unique constraints in the database, and we need to make changes that can violate these constraints. In other words, we would need to remove the object and create a new one, but with the same identifier.

    Let’s modify our Person class and make its Oid field not auto-incremented:

    [Key]
    public int Oid {
        get { return oid; }
        set { SetPropertyValue<int>("Oid", ref oid, value); }
    }

    And then do the following:

    using(ExplicitUnitOfWork euow = new ExplicitUnitOfWork(dataLayer)) {
        //Load the object with a key ‘5’
        Person person = euow.GetObjectByKey<Person>(5);
    
        //Delete it
        euow.Delete(person);
    
        //Save the changes within a transaction
        euow.FlushChanges();
    
        //Create a new object with a key ‘5’
        Person personNew = new Person(euow);
        personNew.Oid = 5;
        personNew.Name = "Thomas Brown";
        personNew.Age = 34;
    
        //Save everything and close the transaction
        euow.CommitChanges();
    }

    We have also created another example demonstrating the use of the ExplicitUnitOfWork class. You can download it and check it out, after 2010.2 ships. In this sample you will see:

    “…a general solution, showing how to use the ExplicitUnitOfWork class to generate sequential numbers, that can then be used as user-friendly identifiers in documents, as invoice line numbers, etc. Here, as opposed to the solution shown in the A2213 KB Article, the ExplicitUnitOfWork class is used to ensure that the assignment of the sequential number will be a part of a database transaction that results in the successful saving of the document. Hence, the current solution will also work in a scenario with high-volume of concurrency transactions.”

    That’s all for this blog post, ‘til next time, happy XPO’ing! Smile

  • XAF – ASP.Net Applications UI Improvements (Coming in V2010 Vol 2)

         

    The 2010.2 version of XAF will see improvements to the UI of ASP.Net applications. Below I have enumerated some of these changes so that you can see what we are planning. Don’t forget to let us know what you think in the comments.

    1. The first thing we’ve done is to improve the general layout of elements on the page. Previously, XAF web apps looked more like a web page, you know, with elements just “floating around in the air”. However, an XAF web app isn’t really an informational web site, it’s actually a rich internet application and so we’ve decided to improve the UI. Now the layout is more compact with functional regions having clearly defined borders. As a result, we waste much less of the screen real estate.

    Element layout before

    Before

    Element layout after

    After

    2. Next we added a splitter, which separates the left panel and working area. This splitter allows you to collapse the left panel, enlarging the working area, enabling you to view more data. The splitter also allows you to fine-tune the width of the left panel.

    Before - no splitter

    Before

    After- with splitter

    After

    3. Then we introduced support for informational panels that allow you to display data of any kind, wherever required.

    4. We’ve also freed up some additional work area space by moving the breadcrumb navigation under the view title, thus consolidating two related items – the view and the path to it.

    Before - breadcrumb placement

    Before

    After - breadcrumb placement

    After

    5. We have removed the object navigation Actions from the main toolbar while at the same time compacting and accenting their appearance. As a result we have freed additional space on the toolbar for other Actions and visually separated a functional UI element.

    Before - object navigation placement

    Before

    After - object navigation placement

    After

    6. Actions from the Save category have been removed from the main toolbar and are now available in a separate Action group. This group is displayed at the top and bottom of a View. Doing this means:

    a. We clearly notify a user when he enters edit mode, as the Save Actions only appear in this mode;

    b. We have visually separated a functional Action group;

    c. We have freed toolbar space for other Actions;

    d. We have made control of modifications look more like other web applications where, generally, changes are saved or cancelled via buttons located at the bottom of a form.

    Before - save action placement

    Before

    After - save action placement

    After

    7. Support for all of the DevExpress ASP.NET themes has been introduced, so that a user can now choose a theme best suited to their way of using the application.

    Well that’s all for this short blog post. Don’t forget to let us know what you think in the comments. Until next time, happy XAF’ing! Smile

  • XAF – Template Improvements (Coming in V2010 Vol 2)

         

    Stick three UI designers in a room and ask them to come up with a UI design solution for a particular problem and you are going to get three different designs? Why’s that? Well because, although there are good guidelines on UI design in general, UI design is more art than science and so personal taste comes into play. The bottom line is that there is no, correct, general UI solution for a particular problem. Now that kind of sucks for us because, in case you hadn’t noticed, XAF is an application framework that ships with a UI. By definition, this UI must be a general one and that means that most of our customers are going to want to change the UI most of the time.

    Well good news! As of 2010.2 that’s going to be a lot easier! Up until now, when you’ve customised your templates, all’s been well until we’ve released a new version of XAF, in which we’ve updated the templates, and now look, you’ve got to merge your changes in with ours, and that’s no fun. Well we’re looking to make things a lot simpler in 2010.2. So, how have we done this? Well, firstly we’ve moved all of the residual logic out of the templates and into base classes or helper classes or into new components entirely. This means that, in future, when we improve our templates, these improvements will actually be added to these classes and will not affect your customisations. Secondly, we’ve improved design time support and ensured that all of our templates can be customised, for example you can easily add a new custom action controller:

    Design time support for template customisation

    And thirdly, we’ve introduced a special CustomizeTemplateViewControllerBase controller that will make your life easier if you are adding panels to your customised template.

    Okay, so let’s take a look at all of this in action by customising the main form template to include a custom panel. First thing we have to do is to get a hold of the template and include it in our project, then we are going to add the panel by opening the designer, changing the view site’s Dock property from Fill to None and dropping a SplitContainerControl nearby. Next, we’ll drag and drop the view site onto the SplitContainerControl’s first panel and set the view site Dock property to Fill:

    Add a new panel to the main template

    Then we’ll set the SplitContainerControl’s Dock property to Fill and set the SplitContainerControl’s FixedPanel to Panel2 (to ensure that it is the left panel that can be resized), before setting the SplitContainerControl’s PanelVisibility to Panel1, to make the right panel invisible by default.

    Having done that, we need to put some info on the SplitContainerControl’s panel. Let’s display a hint, based on the current View, and store the hint in the Application Model, so that it can be edited via the Model Editor. So, firstly, we extend the Application Model, to add a new Description property to View nodes:

    public interface IModelViewDescription {

        string Description { get; set; }

    }

     

    public override void ExtendModelInterfaces(ModelInterfaceExtenders extenders) {

        base.ExtendModelInterfaces(extenders);           

        extenders.Add<IModelView, IModelViewDescription>();

    }

    Secondly, we need to display this information on a panel. To do this, we are going to implement a platform-agnostic controller and platform-specific descendants. The platform-agnostic Controller will be derived from the built-in CustomizeTemplateViewControllerBase<TemplateType> Controller. Where TemplateType can be either a template type or an interface implemented by templates. The CustomizeTemplateViewControllerBase already provides template access logic, so our code wont be that complicated:

    public abstract class InfoPanelsViewControllerBase<TemplateType> : CustomizeTemplateViewControllerBase<TemplateType> where TemplateType : IFrameTemplate {

        private string GetInfoText() {

            return ((IModelViewDemoDescription)View.Model).DemoDescription;

        }

        protected abstract void SetInfoTextToControls(string text);

        protected override void UpdateControls(View view) {

            SetInfoTextToControls(GetInfoText());

        }

        protected override void UpdateControls(object currentObject) {

            SetInfoTextToControls(GetInfoText());

        }

        public InfoPanelsViewControllerBase() {

            TargetObjectType = typeof(InfoPanelsObject);

        }

    }

    Now we can derive a Windows Forms specific descendant. Before we do that though, let’s define an interface, through which we’ll access the template’s panel, allowing us to decouple the controllers from the templates.

        DevExpress.XtraEditors.SplitContainerControl SplitContainer { get; }

    }

    Implement this in the template:

    #region IInfoPanelTemplate Members

    DevExpress.XtraEditors.SplitContainerControl IInfoPanelTemplate.SplitContainer {

        get { return splitContainerControl; }

    }

    #endregion

    Finally, let’s write the Windows Form specific controller that interacts with the template’s panel:

    public class InfoPanelsViewController : InfoPanelsViewControllerBase<IInfoPanelTemplate> {

        private GroupControl panel;

        private LabelControl literal;

        private void UpdateInfoPanelVisibility(SplitContainerControl splitContainer) {

            splitContainer.PanelVisibility = splitContainer.Panel2.Controls.Count > 0 ?

                SplitPanelVisibility.Both : SplitPanelVisibility.Panel1;

        }

        private void EnsureControls() {

            if(panel == null) {

                panel = new GroupControl();

                panel.AutoSize = true;

                panel.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;

                panel.Dock = System.Windows.Forms.DockStyle.Top;

                literal = new LabelControl();

                literal.Dock = System.Windows.Forms.DockStyle.Top;

                literal.AutoSizeMode = LabelAutoSizeMode.Vertical;

                panel.Controls.Add(literal);

                panel.Text = "Contextual Panel";

            }

        }

        protected override void SetInfoTextToControls(string text) {

            if(literal != null) {

                literal.Text = text;

            }

        }

        protected override void AddControlsToTemplateCore(IInfoPanelTemplate template) {

            EnsureControls();

            template.SplitContainer.Panel2.Controls.Add(panel);

            UpdateInfoPanelVisibility(template.SplitContainer);

        }

        protected override void RemoveControlsFromTemplateCore(IInfoPanelTemplate template) {

            template.SplitContainer.Panel2.Controls.Remove(panel);

            UpdateInfoPanelVisibility(template.SplitContainer);

            panel = null;

            literal = null;

        }

    }

    Now, if we launch the application, go to the model editor and add a description for a View, we should see:

    View showing description

    Of course we can do exactly the same thing in a Web Form View, by following the same steps as above (omitted here):

    View showing description

    I hope you can see how this this new feature, coming in 2010.2, will increase your productivity by making it much easier for you to customise our templates, and to maintain those customisations in the face of us releasing improved templates in the future.

    That’s all for this post, until next time, happy XAF’ing! Smile

  • XAF - ASP.Net Theme Support (Coming in V2010 Vol 2)

         

    Whilst DevExpress make fourteen beautiful themes available to our ASP.Net controls customers, it has long been a source of annoyance to our XAF customers that there is no easy way to use those themes in an XAF ASP.Net application. Well good news! As of V2010 Vol 2 that will no longer be the case!

    When you create an ASP.Net XAF application, it will contain the Aqua theme. If you include modules in the application, which use additional controls, like the scheduler for example, then you have to deploy additional skin files (or a completely new theme) using the Theme Deployer.

    Web application showing the Aqua theme

    This tool can also be used to deploy additional themes. When several themes are deployed, you can choose the default one using the standard ASP.NET approach – by specifying the pages element in the application’s Web.config configuration file:

    <configuration>
      <system.web>
        <pages theme="Aqua" />
      </system.web>
    </configuration>
    

    End-users can also switch between deployed themes via the new Choose Theme Action. The selected theme is persisted in the user’s browser cookies. So, the theme will be applied every time a user uses the application.

    Web application showing the Silver theme

    And with that little bit of good news for XAF web application developers, I’ll leave you. So, until next time, happy XAF’ing! Smile

  • XPO – Training London UK, January 2011

         

    Following hard on the heels of my post about 3rd party training for XAF, comes news of a new training event for XPO. Oliver Sturm is offering an “Expert XPO” class in London in the new year. Oliver says of the class:

    “This class is a deep dive into DevExpress eXpress Persistent Objects, short XPO. XPO is an object/relational mapping (ORM) tool with a brilliant feature set, lending itself equally well to small and large development projects. With its broad database and platform compatibility as well as support for new technologies like Silverlight and Azure, XPO is a valuable proposition for many scenarios that competing tools don’t cover. As the basis of the eXpressApp Framework (XAF) product, a business application framework also made by DevExpress, XPO has additional credibility. The class starts with the basics, but moves on quickly to advanced scenarios. As much as the two-day timeframe allows, no question about XPO shall remain unanswered!”

    The class will run from January 27 – 28 2011 and registration is open now, with an early bird discount available until the end of November. For more details, check out Oliver’s blog.

  • XPO – Uncoupled from ADO.Net Providers (coming in V2010 Vol 2)

         

    We all know that loosely coupled is better than tightly coupled, but that’s not a principle we’ve been able to follow all the time here at Devexpress. For example, XPO is pretty tightly coupled to ADO.Net, which is not at all ideal. That is something that we are going to change – as far as we can – with the 10.2 release. What that means in reality is that XPO will have no direct reference to most of the ADO.Net providers, but instead it will reference only System.Data.SqlClient, System.Data.OleDb (for MS Access support) and VistaDB. We cannot remove the reference to the later as it provides its own specific interface for working with the schema. However, at the moment, the future of this database is not at all clear, so that problem me disappear over time.

    So how do we work with the other providers but maintain a loose coupling? Well, simply, we load these other providers dynamically. This means that you will not be tied to a specific version of the provider, you can easily use the latest version without having to recompile the DevExpress.Xpo.Providers assembly, configuring assembly binding redirections or waiting for updates from us! At last, no more “Could not load file or assembly 'MySql.Data, Version=XXX…or one of its dependencies. ” errors! Having said that, you should still only use the providers that are currently supported by XPO, as only these are tested and guaranteed to work.

    Of course, these changes wont affect performance in any way as we still use the standard ADO.Net interfaces or delegates prepared with the provider. Since all the changes are made internally, you wont have to change any of your code to take advantage of this extra freedom!

    That’s all from this short (but sweet) post, until next time, happy XPO’ing Smile

  • XPO – Only Update Modified Properties (coming in V2010 Vol 2)

         

    As you may or may not know, when you save a persistent object to the database, XPO includes all of the properties in the update command, regardless of whether or not they have been modified. The reason for this is that it doesn’t make any difference to the database server whether you update one or many columns in the row – for most use cases – whilst it allows us to save on memory overhead by not having to “remember” which properties had changed and which had not.

    Now we realise that “most cases” are not *all* cases and so you might have problems with this design decision, especially if you are processing a lot of rows at once, or if your properties contain large amounts of binary information. Of course, the facility has always existed (well since 2006 anyway) to overcome this problem, but to be honest, it required you to do a quite a bit of work, inheriting from Session and overriding certain methods. As an aside, if you wish to know how to solve this problem, currently, then check out this blog post by Michael Proctor, a customer and DX Squad member.

    Anyway, we’ve decided to make your lives a lot easier going forward. As of 10.2 we’ve introduced the UpdateModifiedOnly parameter into the DelayedAttribute. Setting this parameter to true ensures that the related property is only sent to the database for update if it has actually been modified. But, enough talk, let’s have a look at some code to illustrate it’s use:

    using DevExpress.Xpo;
    
    public class Person : XPLiteObject 
    {
        int oid;
        string name;
        XPDelayedProperty data;
        
        [Key(true)]
        public int Oid {
            get { return oid; }
            set { SetPropertyValue<int>("Oid", ref oid, value); }
        }
    
        public string Name 
        {
            get { return name; }
            set { SetPropertyValue<string>("Name", ref name, value); }
        }
    
        //DelayedAttribute(string fieldName, bool updateModifiedOnly)
        [Delayed("data", true)]
        public byte[] Data {
            get { return (byte[])data.Value; }
            set { data.Value = value; }
        }
    
        public Person(Session session): base(session) {}
    }

    and this is how we can test the new feature:

    //...
    using DevExpress.Xpo;
    using DevExpress.Xpo.DB;
    //... 
    byte[] dataFirst = new byte[] { 0x11, 0x22 }; byte[] dataSecond = new byte[] { 0x21, 0x32 }; int personOid; using(UnitOfWork uow = new UnitOfWork(dataLayer)) { Person person = new Person(uow); person.Name = "Thomas Brown"; person.Data = dataFirst; uow.CommitChanges(); //Remember the OID of the object personOid = person.Oid; } using(UnitOfWork uow = new UnitOfWork(dataLayer)) { Person person = uow.GetObjectByKey<Person>(personOid); person.Name = "James Brown"; byte[] data = person.Data; uow.CommitChanges(); // Updated in the database: Oid, Name person.Name = "Stiven Brown"; person.Data = dataSecond; // Change the Data property uow.CommitChanges(); // Now updated in the database: Oid, Name, Data }

    As you can see this is a lot easier now. This facility wont be needed for every property, but if you are using BLOBs in your application, this is the functionality you have been waiting for!

    That’s all for this post, ‘til next time, happy XPOing! Smile

  • XPO – Direct SQL Queries

         

    In the comments to my previous blog post about executing stored procedures from XPO, you asked how you could execute a SQL query from within a persistent class, so in this post I thought I’d show you how it is done.

    Taking an example from the previous post where Form1 contains a UnitOfWork, a XPDataView and a GridControl, and where XPDataView is a data source for a GridControl.

    Firstly, you can simply execute the query, for example, the update discounts for orders:

    public void UpdateDiscount(out int affectedRows) 
    {
        affectedRows = unitOfWork1.ExecuteNonQuery("UPDATE [Northwind]" +
            ".[dbo].[Order Details] SET [Discount] = 0.15 WHERE "+
            "[UnitPrice] > 50");
    }

    Secondly, you can request and obtain a scalar value, for example, if you need to know the number of orders from a specific employee:

    public int GetEmployeeOrdersCount(int employeeId)
    {
        return (int)unitOfWork1.ExecuteScalar(string.Format(
            "SELECT COUNT(*) FROM [Northwind].[dbo].[Orders] " +
            "WHERE [EmployeeID] = {0}", employeeId));        
    }

    Thirdly, you can run a query that returns a result set:

    using DevExpress.Xpo.DB;
    //…
    public SelectedData GetEmployeesSimpleData() 
    {
        return unitOfWork1.ExecuteQuery("SELECT EmployeeID, (FirstName + ' ' " +
            "+ LastName) as Name, City, Country FROM " +
            "[Northwind].[dbo].[Employees]");
    }

    You will have to describe the class so that the data can be loaded into objects or a XPDataView:

    [NonPersistent]
    public class EmployeeSimple : XPLiteObject 
    {
        [Key]
        public int EmployeeID;
        public string Name;
        public string City;
        public string Country;
        public EmployeeSimple(Session session) : base(session) { }
    }

    And since the order of fields in the class is the same as the order in the query, then the objects can be loaded as follows:

    public ICollection<EmployeeSimple> GetEmployeesSimple()
    {
        return unitOfWork1.GetObjectsFromQuery<EmployeeSimple>("SELECT " +
            "EmployeeID, (FirstName + ' ' + LastName) as Name, City, Country " +
            "FROM [Northwind].[dbo].[Employees]");
    }

    To load data into the XPDataView simply amend the  Form1_Load event as follows:

    private void Form1_Load(object sender, EventArgs e)
    {
        //Fill information about the properties of a class EmployeeSimple
        xpDataView1.FillProperties(unitOfWork1.GetClassInfo<EmployeeSimple>());
    
        //Load the data
        xpDataView1.LoadData(GetEmployeesSimpleData());
    }

    Executing that code will give you the following result:

    Form with data result

    If you don’t want to show all the fields, or if their order differs from the request, then you can provide additional information to obtain the correct fields in the correct order:

    public SelectedData GetEmployeesDataForOrderExample()
    {
        //Fields are mixed, and the field 'City' removed from the query
        return unitOfWork1.ExecuteQuery("SELECT (FirstName + ' ' + LastName) " +
        "as Name, Country, EmployeeID FROM [Northwind].[dbo].[Employees]");
    }
    
    //Array to specify the order of the fields in the query
    static LoadDataMemberOrderItem[] employeesLoadOrder = new LoadDataMemberOrderItem[] 
    {
        new LoadDataMemberOrderItem(2, "EmployeeID"),
        new LoadDataMemberOrderItem(0, "Name"),
        new LoadDataMemberOrderItem(1, "Country")
    
    };

    And once again modify the Form1_Load event:

    private void Form1_Load(object sender, EventArgs e)
    {
        XPClassInfo employeesClassInfo = unitOfWork1.GetClassInfo<EmployeeSimple>();
    
        //Using an array employeesLoadOrder
        xpDataView1.FillPropertiesOrdered(employeesClassInfo, employeesLoadOrder);
        xpDataView1.LoadOrderedData(employeesLoadOrder, GetEmployeesDataForOrderExample());
    }

    To get the following result:

    Results form with reduced fields

    I hope that answers some of your questions regarding SQL queries with 2010.2.

    That’s all for this post, so until next time, happy XPOing! Smile

  • XAF - Improvements to The Printing and Reporting Modules (coming in V2010 V2)

         

    Here at DevExpress we like to get feedback, from our customers, regarding our products. Not only do we like to get that feedback but we like to act on it too. In response to what you have told us, we have made a number of improvements to the Printing and Reports modules for the upcoming v2010 vol2 release. In this post, I will outline the most important of these.

    Printing of nested List Views

    We have added the Print Preview Action to nested list views, enabling you to quickly print that table:

    NestedPrinting

    Weakly associated collections in the report designer

    Up until now, if a collection property did not have the Association attribute applied, the collection was not available in the report designer. This was a real drawback as it effectively prohibits use of non-persistent object collections in reports. It was also an issue for persistent object collections, since adding unnecessary associations can impact the performance of the application. So, in v2010 vol2 we have resolved the issue and now all collection properties are available in the report designer.

    The following screenshot is taken from the MainDemo application, which is shipped with XAF. The ChangeHistory Detail Report represents a collection of object changes tracked by the Audit Trail module. This collection is not decorated with the Association attribute and, prior to v2010 vol2, it would be simply unavailable in the report designer.

    ReportCollections

    Tabbed MDI in the report designer

    As you already know, with the upcoming release of DXperience, the end-user reports designer has been improved to support Multiple-Document Interface (MDI).  More information on this can be found by following this link:

    http://community.devexpress.com/blogs/theprogressbar/archive/2010/08/11/mdi-end-user-reports-designer-for-xtrareports-coming-in-v2010-vol-2.aspx

    The good news is that this functionality will be available in XAF v2010 vol2 too! So, you can now edit several reports at once, quickly switch between them to copy/paste report data or import/export a layout. The Open command from the File menu now loads the application’s report into a new tab.

    Report wizard in the report designer

    Along with the support for MDI, we have introduced a the “New with Wizard” Action into the file menu. So, you can now easily create new reports without leaving the report designer.

    NewWithWizard

    Subreport support

    The v2010 vol2 version of XAF also includes support for subreport functionality. So now you can easily include a particular report structure into many reports, keeping a consistent appearance and functionality.

    Subreports

    Enumeration and reference type XtraReports Parameters

    The XtraReports Suite, used by the Reports module, has native support for creating custom parameters to be used when filtering a report data source. However, previously only simple value type parameters such as String or Boolean were supported.

    Parameters1

    Therefore, it was not possible to use these parameters for filtering a report data source, say by the value of a reference property. That is why in XAF, the report designer introduced additional filtering properties where you could use XAF parameters which can be of any type.

    With the v2010 vol2 release, this limitation no longer exists as we have implemented support for enumeration and reference type parameters.

    Parameters2

    Now you can create custom XtraReports native parameters of any type and use them to specify filtering criteria via the FilterString property.

    As a result of this improvement, the XAF-specific filtering properties are no longer needed and are now deprecated. They are going to be removed in future releases. For now, we recommend that you switch to using the FilterString property and XtraReports parameters as XAF parameters are being deprecated anyway. More on this in a coming post on filtering improvements in XAF.

    That’s it for this post, until next time, happy XAFing! Smile

  • XAF Training From Freelander Solutions Developer

         

    Are you an XAF user? Based in Europe and looking for some training? Well you are in luck! Freelander Solutions Developer of Spain are offering training in Barcelona from November 22-25.

    The company themselves are no strangers to XAF, they are pioneers of using XAF in Spain. They have developed CustomGest, their own line of products.

    The objectives of the course are to analyse real use cases using XAF. Emphasis will be placed on the most effective way for each requirement to be engineered, with an eye to performance, security, maintainability, module organisation, and deep UI customisation.

    For more information about the course, or to register, check out the page on their web site.

More from DevExpress
Live Chat
Have a pre-sales question?
Need assistance with your evaluation?
We are here to help.
Chat is one of the many ways you can contact members of the DevExpress Team. We are available Monday-Friday between 8:30am and 5:00pm Pacific Time.
If you need additional product information, require pre-sales assistance, or want help with your order, write to us at info@devexpress.com or call us at
+1 (818) 844-3383.