Search This Blog

Monday, April 29, 2013

The best platform-agnostic solution on how to display a dialog window (to gather user input) from a business object

Based on the number of occurrences in the Support Center I feel that not many of you know that with XAF it is possible to invoke a dialog window from a business object context and do so without using any controllers or methods of the XafApplication class (these solutions are based on configuring the ShowViewParameters object or a ViewShortcut).

The solution I would like to tell you is to create a method marked with the ActionAttribute and accept a non-persistent object as a parameter. XAF will recognize such a method and generate a PopupWindowShowAction for it in the UI.

Gatheruserinputfrombusinessobjectcontext

When you execute this command, XAF will show a DetailView of a specified non-persistent object. Since XAF generates Views based on your data model, your can code your non-persistent object to contain required input fields. Of course, you achieve a more complex UI by providing custom editors, customizing layout, etc.

Refer to the "Create An Action that Displays the Pop-up Dialog" section of the How to: Create an Action Using the Action Attribute help article for more details and a complete example.

I think that this platform-agnostic solution is best for simple scenarios where:

  • you need to gather input from end-users and execute a custom business logic based on the gathered data;
  • your custom logic is not complex and deals with the current and related persistent objects only.

You may also be interested in a more complex and flexible example on the subject:

http://www.devexpress.com/example=E760

However, I believe that for such complex scenarios it is best to use a Controllers, which is not only more natural (normally, it is best practice for business objects not to be tied to a UI or deal with UI-related entities), but is aslo more flexible as you have full control over the UI and not limited to the business object scope.

 

I hope this helps.

Thursday, April 25, 2013

Создание повторно используемых бизнес моделей с помощью технологии Domain Components (XAF)

Недавно выступал на встрече GETDEV.NET c кратким обзором нашей технологии Domain Components (DC). Вот небольшая аннотация к докладу:

"Задумывались ли вы когда-нибудь, что с переходом от SQL к DataSet, а затем и к ORM типа Entity Framework развитие технологий для доступа и управления данными приостановилось? Что еще нового можно придумать к уже привычному оперированию записями таблиц БД как объектами CRL и при этом поднять удобство разработчика на следующий уровень? На этот и другие вопросы попробует дать ответ доклад о технологии Domain Components (часть DevExpress eXpressApp Framework), которая облегчает создание повторно используемых бизнес моделей за счет легкого комбинирования путем использования интерфейсов вместо классов (это позволяет вам эмулировать "множественное наследование" в C# и VB.NET), а также свободы от особенностей конкретной ORM."

Слайды презентации можно скачать вот тут:

http://www.slideshare.net/kaatula/domain-components

Видео (примерно на час) доступно на YouTube:

P.S.
Докладчика просьба строго не судить, так как это его третье публичное выступление:-)

Friday, April 19, 2013

The capability to not mark a persistent object as modified for saving if only its non-persistent properties were changed

I am not sure if this will be helpful for many XPO customers, but there is definitely a number of scenarios where you may welcome the implemented behavior. Refer to the tickets below to learn more.

http://www.devexpress.com/Support/Center/p/Q489119.aspx - implemented in 13.1 where you can use the new XpoDefault.IsObjectModifiedOnNonPersistentPropertyChange and Session.IsObjectModifiedOnNonPersistentPropertyChange properties.

http://www.devexpress.com/Support/Center/Question/Details/Q408356 
http://www.devexpress.com/Support/Center/Issues/ViewIssue.aspx?issueid=S34863 - requested in the past by other customers.

Take special note that in the current version it is already possible to avoid change notifications for non-persistent properties by not using the

OnChanged or SetPropertyValue methods in setters of your non-persistent properties.

Thursday, April 18, 2013

EasyTest: Referring to an UI element by its Id rather than by caption when writing a functional test

As you probably know, our functional testing framework - EasyTest, finds or identifies UI elements by their captions by default. This is natural and allows non-developers to easily create functional tests based on what they see on the screen.

However, sometimes there may be several elements with the same caption on the screen or their captions may be too long or inconvenient to use in the script. EasyTest also provides a solution for such scenarios and allows you to use the control's identifier instead of its caption right in the script! Let me demonstrate you how to use this hidden feature.

Step 1. Enable the Dianostic Action in the application configuration file:





Step 2. Navigate to the required UI screen and display the EasyTest Control diagnostic info:





Step 3. Find the required UI element identifier:





Step 4. Use the obtained identifier in the EasyTest script:




The demonstrated functionality is available for WinForms apps only.
Anyway, I hope you will find this small trick helpful!

Monday, April 15, 2013

Improving usability with regard to formatting property values

As you probably know, formatting property values in XAF is typically done in a platform and control-agnostic manner in the Application Model via the Model Editor (the same is of course possible in code). Now it is also possible to define formatting for a value type in a single place for all business class properties, thus saving your time.
For more details, I would like to quote myself from http://www.devexpress.com/issue=S31518:

"Starting with version 13.1, you will have a single place for setting the DisplayFormat and EditMask properties for a type, because the IModelRegisteredPropertyEditor interface has been extended with respective properties. This improvement is mainly supposed to reduce the duplicate work when providing default formatting for common types like System.DateTime, Decimal, Integer, Double, etc.
As expected, these defaults will be automatically propagated to class members, ListView columns and DetailView editors, with the capability to provide custom values at these levels.
Take special note that now PropertyEditors use the default formatting from the application model, or from the DevExpress.ExpressApp.Editors.FormattingProvider singleton if the model is not available. If you build a custom PropertyEditor that does not require any default formatting, you can empty the aforementioned properties in the application model for your business class property or apply ModelDefaultAttribute to it in code."

Screenshot


Hopefully, you will like this small usability improvement. Please let me know your thoughts in comments.

Friday, April 12, 2013

Where do you usually store application and user settings?

I would like to quote myself from http://www.devexpress.com/issue=Q488085 as I believe that many other XAFers will be interested in this discussion:

"There are several good ways to store settings in XAF:
1. Use a persistent singleton class

2. Use the Application Model
For instance, you can implement a custom model extension that will hold the value and then create another element that will have a list of the first elements. Of course, the application model can be physically stored in the database, if required.

3. Use the ValueManager class (How to save an application's settings at runtime and then access them via a common interface from both Windows Forms and ASP.NET platform-dependent modules (Example)).

4. Use any other solution you would use for the same task in a regular non-XAF application."

Personally, I think that #1 and #2 are good.

Feel free to leave comments if I missed some cool places or ways to store settings;-)

Localizing apps becomes a bit easier

If you localize apps via the XAF's Localization Tool, you might face a need to skip certain captions, because they happened to be the same in your native language. For instance, the "Name" and "Navigation" are also "Name" and "Navigation" in German:-)

Althought it was already possible to do this by just copying the value manually into the column with translated values, starting with version 13.1 there is a better way of doing this. You can now just select required captions and update them at once via the new Mark As Translated command from the context menu:


View on screencast.com »

It is especially helpful when you have lots of such matches.

Thanks to our loyal customers from France (Julien) and Germany (Christian) who pointed us to this small improvement. Refer to the following Support Center tickets to learn more about their stories and real-life experiences:

http://www.devexpress.com/Support/Center/Issues/ViewIssue.aspx?issueid=S138506

http://www.devexpress.com/Support/Center/Question/Details/Q394260

Happy XAFing!

Edit multiple records in a ListView and save the changes at once

Do not miss one more cool contribution from the XAF community (thanks Nick Blake) at
SystemModules - Make it possible to edit multiple records in an editable ListView at once and save the changes only when needed


View on screencast.com »



BTW, you may be interested to know that the standard ListViewAutoCommitController and DetailViewController classes were refactored into a single and more powerful ModificationsController one in version 13.1. Please add this ticket into your Support Center favorites to learn more about this feature.

Thursday, April 11, 2013

A platform-agnostic solution to prevent sorting or grouping by a certain ListView column

Today I have refactored one of my examples: http://www.devexpress.com/example=E1254 and want to remind you about it.


View on screencast.com »

Hopefully, you will find the demonstrated solution not only helpful for your project, but you will also recognize the popular pattern of extending the Application Model and try doing the same in your project to accomplish your custom tasks. In short, it is helpful when you want to control certain UI flow or settings at runtime, declaratively and without writing any code from project to project. For instance, once you implemented the model extension in your module, you can specify custom attributes via the Model Editor at both design and run time and then write code that will do something helpful (e.g., disable grid columns sorting and grouping capabilities) based on them.

To get more inspiration, visit the eXpand Framework's site where you can find hundreds of similar extensions for free. To learn more on how to implement such things yourself, study the example's description and code adn then check out the Extend and Customize the Application Model in Code help article.

P.S.
Some of you (well, let's be honest, many of you:-) ) may ask: why are not these AllowSort or AllowGroup attributes available by default in the framework? Well, imagine that we added them, and then another customer asked for some other cool option. OK, we added it as well and so on. Eventually, will will end-up with a hundred of properties in the application model and the property grid with them will not be usable at all. In addition, the original idea of having generalized and independent from UI and controls abstractions for list and detail form, column, editor will evaporate like smoke. You can find more interesting thoughts on this tough subject at http://community.devexpress.com/blogs/eaf/archive/2006/03/28/applying-styles-to-a-view.aspx (even though this blog post is quite old, the ideas shared in it are still valid nowadays).

Recent XPO improvements to the visual designer and OData

Just a small update to to ensure that you have not missed the subject and added it to your development arsenal:

  • S171017 - ORM Data Model Wizard - Make it possible to apply custom attributes for association properties (coming in 13.1)
  • S170003 - ORM Data Model Wizard - Provide the capability to copy properties between persistent objects (coming in 12.2.8)
  • S170964 - XpoDataServiceV3 - Provide a virtual method to create a custom Session (coming in 12.2.8)

    How to leverage the latter functionality is described at Exposing Domain Components (DC) via OData for mobile apps
  • As you probably know, the next maintenance update (12.2.8) is on its way. Once it is officially out, do not forget to check out its change log that contains information about both fixed issues and implemented suggestions, as well as updates to our documentation.

    Wednesday, April 3, 2013

    Exposing Domain Components (DC) via OData for mobile apps

    As you probably know, it is possible to use DC in non-XAF applications as described at eXpressApp Framework > Task-Based Help > How to: Use Domain Components in non-XAF Applications

    So, I will use a similar approach in my XPO-based OData Service project (you can learn more on how to create it via the wizard here). Once I created the service, I will have to modify my XpoDataServiceV3 descendant as shown below:

    [JSONPSupportBehavior]
    public class DCDataService : XpoDataServiceV3 {
        static XPObjectSpaceProvider objectSpaceProvider = null;
        static readonly DataService1Context serviceContext =  new DataService1Context("XpoContext",
            "DevExpress.ExpressApp.DC.GeneratedClasses", CreateDataLayer()
        );
        protected override UnitOfWork GetSessionCore(IObjectLayer objectLayer) {
            if (objectSpaceProvider != null) {
                XPObjectSpace os = (XPObjectSpace)objectSpaceProvider.CreateObjectSpace();
                return (UnitOfWork)os.Session;
            }
            return base.GetSessionCore(objectLayer);
        }
        static IDataLayer CreateDataLayer() {
            XpoTypesInfoHelper.ForceInitialize();
            var typesInfo = XpoTypesInfoHelper.GetTypesInfo();
            var xpoTypeInfoSource = XpoTypesInfoHelper.GetXpoTypeInfoSource();

            typesInfo.RegisterEntity("Survey" typeof(ISurvey));
            typesInfo.GenerateEntities();         

            var connectionString = "Integrated Security=SSPI;Pooling=false;Data Source=(local);Initial Catalog=TestDb";
            var dataStoreProvider = new ConnectionStringDataStoreProvider(connectionString);
            objectSpaceProvider = new XPObjectSpaceProvider(dataStoreProvider, typesInfo, xpoTypeInfoSource, true);
            objectSpaceProvider.CreateObjectSpace(); // Force the objectSpaceProvider.DataLayer property initialization.
            XpoDefault.DataLayer = objectSpaceProvider.DataLayer;
            DevExpress.Xpo.XpoDefault.Session = null;
            return XpoDefault.DataLayer;
        }
    }

    Here I would like to focus on three things:
    1. I initialized the static serviceContext variable and provide the namespace of our auto-generated DC entities as the second parameter: "DevExpress.ExpressApp.DC.GeneratedClasses". It is important to avoid dealing with long-named entities like "DevExpress_ExpressApp_DC_GeneratedClasses_Survey" in our consumer applications.

    2. I initialized the data layer that is used by my XpoContext descendant via the static CreateDataLayer method. There I used some XAF magic, which is required for DC, because domain logic methods accept the parameters of the IObjectSpace type. If I did not use DC, then I would not use the XAF classes in my data service and rather go using pure XPO stuff.

    3. I overrode the GetSessionCore to use the Session created by the XAF's ObjectSpace, again for the correct work of domain logic methods. Take special note that this virtual method is available in version 12.2.8+ only (thanks to our XPO guys for implementing my request so quickly;-)). If you want to test it right away, I have included the latest version of the DevExpress.Xpo.v12.2.Extensions assembly into the demo project I posted here.

    Finally, let me demonstrate why I created the OData service in the first place. Of course, I needed it for my mobile DXTREME application:


    View on screencast.com »


    UPDATE:
    Originally when experimenting with this DC-based service I tried to reference the DcAssembly.dll into my data service project. This cache assembly is automatically generated by XAF when running the application with no debugger attached. So, to get it, I simply ran my XAF WinForms application, which used the same data model, and then copied the generated assembly from the Release/Bin folder into my data service project. Since this assembly contains regular persistent classes instead of DC interfaces (remember my recent talk about different types?), I hoped that this way it might be easier for you to understand and work with. Unfortunately, I had to stop using this undocumented approach later, because it required additional configuration from the application for the correct operation of the DC-based functionality: normally, when XAF loads this assembly internally it also calls the private void ProcessGeneratedAssembly(Assembly generatedAssembly) method of the XpoTypeInfoSource class. Another reason is that with the DcAssembly.dll approach it would also be more difficult to deploy and maintain the app due to the overhead on generating and copying the assembly...

    Monday, April 1, 2013

    Preserving user settings after changes to Application Model extensions

    I obsoleted the IModelListViewWin extension in 13.1 and moved its properties into the core IModelListView interface. Starting with that version the Web Grid and Pivot List Editors will also support setting the active filter functionality. Technically, that means that every List Editor that supports this will implement the following interface:

    namespace DevExpress.ExpressApp.Editors {
        public interface ISupportFilter {
            bool FilterEnabled { get; set; }
            string Filter { get; set; }
        }
    }

    For instance, in the simplest case (ASPxGridView) the implementation can look like this:

            bool ISupportFilter.FilterEnabled {
                get {
                    return Grid.FilterEnabled;
                }
                set {
                    Grid.FilterEnabled = value; ;
                }
            }

            string ISupportFilter.Filter {
                get {
                    return Grid.FilterExpression;
                }
                set {
                    Grid.FilterExpression = value;
                }
            }

    BTW, the IModelListViewWeb.FilterExpression property was obsoleted as well.

    While the majority of you are unlikely touched any of those types and properties in your custom code and thus you, developers, will unlikely be affected by these changes, your end-users quite likely customized filters in your apps. Will they be affected? Hopefully, NOT!

    Since we are good developers and think of our end-users, I of course ensured that their filter customizations are not lost with the new version. In order to do this, I followed the Convert Application Model Differences help article and implemented the IModelXmlConverter interface (honestly, it was already implemented there because there were already a few conversions related to templates) in our System Windows Forms and ASP.NET modules. For instance, this is how it looked in case of the Windows Forms module:

    if (parameters.XmlNodeName == "ListView") {
                    string oldProperty1 = "ActiveFilterString";
                    string oldProperty2 = "IsActiveFilterEnabled";
                    string newProperty1 = "Filter";
                    string newProperty2 = "FilterEnabled";
                    if (parameters.ContainsKey(oldProperty1)) {
                        parameters.Values[newProperty1] = parameters.Values[oldProperty1];
                        parameters.Values.Remove(oldProperty1);
                    }
                    if (parameters.ContainsKey(oldProperty2)) {
                        parameters.Values[newProperty2] = parameters.Values[oldProperty2];
                        parameters.Values.Remove(oldProperty2);
                    }
                }

    I am lucky enough that my real case was rather academical, but if you have a more complicated scenario, XAF also has a solution for you. You can learn more about it in the end of the aforementioned help article.

    To sum this story up, it is always best practice to preserve your end-users settings as much as possible with the new version, because their data is one of the most important things and dealing with it carefully will ensure they will like your application in the end.

     

    So, if you provided custom application model extensions (e.g., there a lot of them in our community project - eXpand that is designed to reduce the amount of code (check this demonstration to learn more) to achieve something) and need to change them, always think about providing a converter like the one above.