Search This Blog


Friday, February 21, 2014

Validation, Conditional Appearance, Security or all modules at once?

I believe this recent discussion in the Support Center will be very interesting for the XAF community.
Let me quote myself from comments to this thread:

Let me comment on the security aspect of this solution. The ConditionalAppearance module (as stated in the docs) should not be used as a security means, even if it can hide or disable certain UI elements. Its primary purpose is to customize the appearance of the application, provide a better UX by guiding an end-user through the predefined application flow (e.g., he or she entered a certain value, then depending on it, new editors appear just for this case or certain editors get disabled not to allow a user to go a wrong way).

So, if you need data protection, you should also have additional security checks (preferably on the server side) and not rely just on the availability of UI controls. For this, I can recommend the following things:

1. Make sure your business logic in data model classes or controllers handles invalid user inputs or other unwanted situations, even if you have set up the Validation or ConditionalAppearance rules for the UI;
2. Use the Security System module to protect your data in the UI or on the server side;
3. Consider hiding your database from the client by using a remote data store service as described in How to connect to a remote data service instead of using a direct database connection;
4. Consider storing the Application Model differences in the database instead of the file system and thus disallowing powerful end-users to customize it manually. See the How to manage user settings (reset, merge, import, export, etc.) stored in the database instead of a file system example for more details.
5. Make sure your application does not allow loading external modules/plug-ins from the configuration file by using the right XafApplication.Setup method overload.

There, of course, may be more things to look at if the final application will be deployed in a banking environment, as in case of the original ticket owner. So feel free to share your feedback on this as well. I know that some of our XAF customers (like Robert Anderson) have production apps working in similar security sensitive environments, so it would be great to hear about your experience. Thanks!

Tuesday, February 18, 2014

AuditTrail module performance improvement in v13.1.10 and v13.2.7

I would like to draw your attention to an improvement we recently made in the AuditTrail module:

AuditTrail - Low performance when saving data under certain circumstances

Please install the version 13.1.10+ or 13.2.7+ and let us know whether it now works better in your app.

I am focusing on this due to a recent discussion in this support ticket. In short, if something is not performing well or fast enough, it is always worth researching the cause of this behavior, rather than disabling a feature completely, especially when it relates to built-in XAF modules.

There may be some tricky or uncovered scenarios, and specialized profiling tools (e.g., AQTime and SQL Server Profiler) may help to find the cause of such performance issues. If you are not so familiar with using profilers (imho, it is still important to master them for the future for any professional developer, though) to profile the project yourself, feel free to send it to us, so that we can research it and find the best solution. I understand that preparing an entire project or test sample may take some time, but the result is worth it. This may also help improve the product itself, and the experiences that other users may be facing, which is always appreciated by the community. Thanks!

Wednesday, February 12, 2014

My Top 10 favorite DevExpress CodeRush features for .NET development in Visual Studio

This is my recent post on HabraHabr (a sort of TechCrunch in Russia) about my favorite CodeRush functions. If you do not understand Russian, try using Google Translate, Google Chrome or just watch the videos from this post.

Wednesday, February 5, 2014

Changing window title when data within a View is modified

Today I have updated one of my examples that shows how to customize a window title to add the asterisk mark when an object in the View is modified:

If you are interested in it, check out the implementation details below:

Basically, this solution consists of a single platform-agnostic WindowCotroller that tracks data changes via the IObjectSpace.ModifiedChanged event and updates the window caption via the WindowTemplateController API. Here you may also want to learn more about other built-in controllers grouped by functionality at Built-in Controllers and Actions.

Wednesday, January 29, 2014

How to traverse and customize XAF View items and their underlying controls

XAF UI screen structure
To better understand how to access and customize XAF building blocks, let's briefly describe how default UI screens are generated in XAF.

On the top of the UI screen structure, there are Windows and Frames linked to Templates (Frame.Template), which are usually platform-dependent entities (e.g., forms, web pages or user controls) defining the Frame's content structure and appearance in the UI. 
There are several types of Frames (both platform-agnostic and platform-dependent), depending on whether their represented UI element has a parent or not: e.g. Frames of the main application form or of a separate dialog form are called Windows, because they are independent and have no parents, while a nested ListView's Frame is not Window.

Here is the respective classes hierarchy for clarity:

      • NestedFrame
      • Window
             • WinWindow
             • WebWindow
                    • PopupWindow

Frame is a container for Controllers (Frame.Controllers or Frame.GetController<T>) that help implement a custom behavior and interaction within a Frame. Note that all application logic and behavior is basically provided by Controllers (both system and user-defined). For easier access, Controllers provide useful properties, events and virtual methods to access the Frame itself and its contents at various points in its life cycle (Controller.Frame, WindowController.Window, ViewController.View, ViewController.ObjectSpace, Controller.Activated, etc.).

Both Frame and Window also serve as a site for a View (Frame.View, ViewController.View). Any View placed within a Frame consists of special sub-elements or items, which represent the actual content of a UI screen. Technically, each of these View elements wraps a certain visual control to display or edit specific data in the UI . View items can be even be complex enough to host other Views.

The placement of content items on the screen, as well as many of their basic settings, are determined by the information from the Application Model corresponding to that View node (e.g., the Views | Address_DetailView node you can see in the Model Editor tool). To learn more on how Views present or lay out their content, check out the following important concepts:
At once, the Application Model is used to preserve the state or current settings of the View and its controls until the next time.

This article is mainly devoted to Views, so please check out the UI Element Overview article if you are interested to learn more on the structure of XAF screens.

View and Item types
The following diagram displays hereditary relations of various View types:

       • CompositeView
              • DashboardView
              • ObjectView
                     • DetailView
                     • ListView

There are also several built-in ViewItem types:

       • ControlDetailItem

       • DashboardViewItem

       • PropertyEditor
             • ListPropertyEditor
             • DetailPropertyEditor
             • WinPropertyEditor
                    • DXPropertyEditor
                          • StringPropertyEditor
                          • ...
             • WebPropertyEditor
                    • ASPxPropertyEditor
                          • ASPxStringPropertyEditor
                          • ...

       • ActionContainerViewItem
              • WinActionContainerViewItem
              • WebActionContainerViewItem

       • StaticText
                • StaticTextDetailItem (DevExpress.ExpressApp.W**.Editors)

       • StaticImage
                • StaticImageDetailItem (DevExpress.ExpressApp.W**.Editors)
       • ...

Remember that for each of these built-in View and Item types there are corresponding elements in the Application Model (IModelDetailView, IModelDashboardView, IModelListView, IModelViewItem, IModelPropertyEditor, etc. that determine their content, layout structure and other options.

The use of certain View items varies and depends on the View type:

    • PropertyEditor and its descendants for various data types, including user-defined and built-in platform-agnostic (ListPropertyEditor,  DetailPropertyEditor) and platform-dependent editors;
    • other ViewItem descendants, including user-defined and built-in ActionContainerViewItem, ControlDetailItem, StaticText, StaticImage, etc.

    • Other ViewItem descendants, including ActionContainerViewItem , ControlDetailItem, StaticText, StaticImage, etc. (user-defined and built-in)

ListView is a special type of View, which consists of  two internal items - ListEditorViewItem and NestedFrameItem. These two service items are undocumented and are not supposed to be used by customers in their code. Instead, ListView provides the additional mechanism for accessing the ListView's content and controls - List Editors.

Traversing View items and their controls
The View, ViewItem and ListEditor abstractions provided by our framework are very often used to access underlying form controls for various customizations. In accomplishing this task, it is common to implement a custom ViewController descendant targeted to a required View type and handle its events or override virtual methods, depending on the moment when you need to perform this customization.

• To access a ViewItem or ListEditor object from a ViewController, it is common to override the OnActicated virtual method (or handle the Activated event) of a custom ViewController class descendant, because View items and List Editors are available right after View creation. Of course, you can use other events and methods which occur later according to the View life cycle.

• To access the underlying control of a ViewItem, it is common to handle the ViewItem.ControlCreated event, while accessing the ListEditor's control usually requires handling the View.ControlsCreated or ListEditor.ControlsCreated events (or overriding the OnViewControlsCreated method) within a custom ViewController class descendant. Of course, you can use other events and methods which occur later according to the View life cycle.

When using this approach, a starting point is almost always the ViewController.View property that gives you access to the underlying elements or API to access them. It is often required to cast the View object to a concrete View type, e.g., DetailView or ListView, to gain access to more View type specific options.

For your reference, here is the list of most popular APIs used to implement common tasks with View items:

    • To identify a ViewItem, use the ViewItem.Id property.

    • To identify a PropertyEditor, use the PropertyEditor.Id or PropertyEditor.PropertyName properties.

    • To access ALL ViewItem objects, you can use the CompositeView.Items property (see Example #1 below).

    • To access ViewItem objects of a specific type, you can use the CompositeView.GetItems<T> method (see Example #2 below).

    • To access a ViewItem object by its Id, you can use the CompositeView.FindItem method (see Example #3 below).

    •  To access a ListEditor object of a certain ListView, use the ListView.Editor property. It is often required to cast it to a specific ListEditor type to access the underlying control and additional options. Refer to the Access Grid Control Properties help article for an example.

    •  To access the underlying control of View items or editors, use the ViewItem.Control or ListEditor.Control properties. Most built-in View items and editors also provide specialized properties for easier access, e.g., GridListEditor.Grid, ASPxPropertyEditor.Editor, ASPxLookupPropertyEditor.DropDown, etc.

Practical implementation considerations
0. Due to WinForms or ASP.NET platform specifics, underlying controls of View items and List Editors may not be immediately ready for customization right after the control is created. It is often required to subscribe to specialized control events indicating their "ready" state:
    WinForms: handle the HandleCreated, VisibleChanged or ParentChanged events of the     System.Windows.Forms.Control object (in certain cases it is even required to apply customizations via the Control.BeginInvoke method).
    ASP.NET: handle the Init, Load or PreRender server side events of the System.Web.UI.Control object or handle the PagePreRender event of the static WebWindow.CurrentRequestWindow object. Of     course, it is also fine to perform certain customizations on the client side via JavaSript.

1. When iterating through the CompositeView.Items collection (via foreach, for or LINQ) to locate a required ViewItem object, it is often helpful to test its type or the ViewItem.Id property, corresponding to the Id property of a respective item node in the Application Model (see Example #1 below).

2. To avoid casting the ViewController.View object to a required View type every time, inherit your custom controller class not from the base ViewController class, but from the generic ViewController<ViewType> or ObjectViewController<ViewType, ObjectType> types, whose View property type will be the same as the specified ViewType parameter (see Example #4 below).

3. Take into account the CompositeView.DelayedItemsInitialization option when writing code that accesses the ViewItem.Control property. Since the default value for this option is true, then in most scenarios it is recommended to handle the ViewItem.ControlCreated event of the required ViewItem object or test whether the properties accessed are null (see Example #2 below). Refer to the Access Editor Settings article for more example code on this task.

4. There are some specifics when accessing items that host or contain other Views inside DetailView or DashboardView. Such Views are typically embedded into a container View with the help of special type of platform-agnostic ViewItem classes:
    • ListPropertyEditor is used to represent collection properties of business objects in DetailView (see Example #4 below);
    • DetailPropertyEditor is used to represent aggregated reference properties of business objects in DetailView (see Example #5 below);
    • DashboardViewItem is used to represent nested Views of any type within a DashboardView (see Example #7 below).

5. Embedded or nested Views are hosted within a NestedFrame, which is technically a descendant of the Frame type with the ViewItem property that can help you identify what is hosted inside it (see Example #8 below).

6. To access a parent View from the ViewItem object, use the ViewItem.View property (see Example #9 below).

7. The View.Control property is very rarely used or should not be used at all. Instead, it is better to use specialized properties of a certain View object, e.g., ListView.Editor.Control, CompositeView.LayoutManager.Container.

8. Certain List Editors (e.g., GridListEditor) may internally instantiate PropertyEditor objects (e.g., for grid column editors) to create underlying controls for viewing or editing business object properties in a ListView. However, these PropertyEditor objects are not "alive" and are primarily only used as a template to create a control. Thus you should not try to access these service PropertyEditor objects in your code via a ViewController.

9. If you need to apply the same global customization to the underlying PropertyEditor control in both ListView and DetailView, then you may consider implementing a descendant of the corresponding PropertyEditor type (and overriding its virtual methods) instead of implementing a ViewController and writing different code for both ListView and DetailView.

10. Normally you should not modify the Application Model information corresponding to a certain View or its items in your code when underlying controls are already created, unless you preserve the current control state into your own model options. When doing so, bear in mind that your model changes will not be taken into account until the next control creation. So, a general rule here is that you either need to customize the control directly or customize the corresponding Application Model options before the control is created and rendered.

11. When ListView and DetailView are shown together (MasterDetailMode = ListViewAndDetailView), you can use the ListView.EditView property to access the embedded detail form and its content.

Check out the following code examples to better understand these points: 

using System;
using System.Linq;
using DevExpress.ExpressApp;
using System.Collections.Generic;
using DevExpress.ExpressApp.Layout;
using DevExpress.ExpressApp.Editors;

namespace MainDemo.Module.Controllers {
    public class MyViewController : ViewController {
        public MyViewController() {
            TargetViewType = ViewType.DetailView;
        protected override void OnActivated() {
            //Example #1
            foreach(ViewItem item in ((DetailView)View).Items) {
                if((item is ControlDetailItem) & item.Id == "Item1") { /*...*/ }
            //Example #2
            foreach(ActionContainerViewItem item in ((DetailView)View).GetItems<ActionContainerViewItem>()) {
                if(item.Control != null) { /*...*/                }
                else {
                    item.ControlCreated += (s, e) => { /*...*/ };
            //Example #3
            PropertyEditor editor = ((DetailView)View).FindItem("Property") as PropertyEditor;
            //Example #4
            ListPropertyEditor editorForCollectionProperty = ((DetailView)View).FindItem("CollectionProperty") as ListPropertyEditor;
            editorForCollectionProperty.ControlCreated += (s, e) => {
                ListView nestedListView = ((ListPropertyEditor)s).ListView;
                NestedFrame nestedFrame = ((ListPropertyEditor)s).Frame as NestedFrame;
            //Example #5
            DetailPropertyEditor editorForAggregatedReferenceProperty = ((DetailView)View).FindItem("AggregatedReferenceProperty") as DetailPropertyEditor;
            editorForAggregatedReferenceProperty.ControlCreated += (s, e) => {
                DetailView nestedDetailView = ((DetailPropertyEditor)s).DetailView;
                NestedFrame nestedFrame = ((DetailPropertyEditor)s).Frame as NestedFrame;
    //Example #6
    public class MyGenericDashboardViewViewController : ViewController<DashboardView> {
        protected override void OnActivated() {
            foreach(DashboardViewItem item in View.GetItems<DashboardViewItem>()) {
                //Example #7
                item.ControlCreated += (s, e) => {
                    DashboardViewItem dashboardViewItem = (DashboardViewItem)s;
                    View nestedView = dashboardViewItem.InnerView;
                    NestedFrame nestedFrame = dashboardViewItem.Frame as NestedFrame;
                    //Example #8                    
                    DashboardView containerView1 = (DashboardView)nestedFrame.View;
                    DashboardView containerView2 = (DashboardView)dashboardViewItem.View;
                    //Example #9                    
                    ViewItem nestedFrameViewItem = nestedFrame.ViewItem;

See Also