Search This Blog

Tuesday, December 30, 2014

About XAF Types Info Subsystem...

I have just closed the DC - Provide support for dynamic members in domain components ticket with two possible solutions (there were some specifics with regard to the late generation of real XPO classes for DC interfaces) and wanted to use this chance to draw your attention to some advanced stuff you may need one day - customizing your data model metadata at runtime via the underlying types info subsystem (ooohhh!)

In short, you may need customizations at this low level when you want to dynamically adjust your ORM data model mappings to the database, add or remove custom members for your data model at runtime (e.g., based on the info stored in the database, XML settings file or any other source) when implementing an app tailored to a specific client/user access rights, etc.

Leaving customizations aside (which is quite rare, to be honest), accessing information about the types (their metadata) registered within the XAF application is really common. For instance:

  • If you want to check what business class this View is for - check the View.ObjectTypeInfo property. 
  • If you want to check the member a PropertyEditor corresponds to - check its PropertyEditor.MemberInfo property.
  • Need to know whether a business class has a certain property? Use the ITypesInfo.FindMember or ITypeInfo.Members APIs.
  • Want to know which code attributes are applied to a class or property?  Call the IBaseInfo.FindAttributes method (check examples here).
  • Want to get/set a class property known only at runtime? Use the IMemberInfo.Get/SetValue methods (see an example in the end of this article - it's like .net reflection, but faster).


Our documentation describes this in several articles here:
eXpressApp Framework > Concepts > Business Model Design > Types Info Subsystem

I have also prepared a small schema to better explain the role this type of info subsystem plays:

As you can see from the schema, this 'types info subsystem' serves as a source for Application Model and thus UI generation. That said, in certain scenarios, you may want to access certain info at a higher level instead of accessing the types info subsystem directly.


If you are anxious to see more advanced XAF stuff today, consider reviewing my previous post at
How to customize the underlying database provider options and data access behavior in XAF.


See Also:
eXpressApp Framework > Concepts > Business Model Design > Data Types Supported by built-in Editors

Friday, December 26, 2014

A sporadic Visual Studio issue with the incorrect Action constructor after modifying Controller (Finally bypassed in 14.2.4!)

Have you ever seen a situation when your Actions defined in the Controller designer worked well, but one day they disappeared from the application UI and were no event present in the Application Model? Unfortunately, we sometimes did, and so did our customers under certain circumstances. The difficulty of this situation is that this annoying behavior in the IDE was truly random and sporadic, as it all might work on the same machine and then fail without any reason under the same circumstances, with no environment changes. This behavior could be reproducible with both new and existing Controllers and Actions. Our Controller/Action/designers code was fine and the same issue could be reproducible even with the standard Component Designer and standard MS components, so it was eventually reported to MS Connect:



This problem was not massive, to be honest, but the reports the report count reached a reasonable threshold within several years... 

Since we still continue to receive reports from our customers on this behavior from time to time, which negatively affects their experience with our product, we decided to introduce a special "hack" on our side, which helps avoid this behavior. This fix successfully worked in our tests with the problematic virtual machines where we happened to semi-stably isolate this strange behavior. This improvement is available starting with version 14.2.4 and I recommend you upgrade to this version if you experienced this behavior in the past.

Hopefully, you will never experience this again, and Happy XAFing/holidays!

An Entity Framework version of our XCRM demo

You might have noticed that starting with v14.2 we made an EF-based version of our popular XCRM show-case demo. It is installed at %PUBLIC%\Documents\DevExpress Demos 14.2\Components\eXpressApp Framework\XCRM\ by default.


Data models and DbContext code are located within the XCRM.Module\Data\ folder for you to explore. These data models are built for real and quite complex scenarios, so you can use this as a reference in addition to our two other Entity Framework demos:

  • %PUBLIC%\Documents\DevExpress Demos 14.2\Components\eXpressApp Framework\EFDemoCodeFirst\
  • %PUBLIC%\Documents\DevExpress Demos 14.2\Components\eXpressApp Framework\EFDemoModelFirst\

Thursday, December 25, 2014

XAF 14.2 webinar recording and other interesting videos

I am late with this announcement, but still want to share a link to the webinar we made in early December where Seth demonstrated certain XAF 14.2 features live and talked about XAF application development in general: 



As always, there was also a Q/A session during the presentation: certain questions were voiced live and others were answered by our XAF team in chat. Frankly speaking, we had hundreds of questions about the new functionalities so our keyboards got hot quickly. We could not even handle all the questions so I am thinking about running another pure QA session around January/February. There we could present the most frequently asked questions and general information about the new bits and maybe present some new developments. Honestly, our team really enjoys such live sessions where we had a chance to talk to each other, ask questions and answer yours. Please let me know what you think of this idea in comments.

You know, Seth Juarez, our Analytics Program Manager at DevExpress, is a presenter from God, so if you are new to XAF or not yet getting the ideas behind it well, I recommend you watch another presentation made by Seth: A Gentle Introduction to XAF.
JFYI.



During the webinar, there was also a survey with a few questions for the auditory. Here are poll results (based on the 154 attendees) for your reference: 


Looking for practical experiences with both DevExpress XPO & ADO.NET Entity Framework


----

You know that XAF supports both ORM libraries to almost the same extent, so there is no noticeable difference at the framework level (see 1, 2, 3) that should affect your choice in favor of a certain data access tool. There are, however, some differences between these ORMs in their functionality, usability, history and other factors which may indirectly affect your choice.



We do not provide comparisons of our products with competitors (mainly from an ethical point of view), but I think it would not hurt anyone if there was a list of proven opinions from users who had practical experience with both ORM tools. I already started collecting this list and among differences our users mentioned was, for instance:

Tuesday, December 23, 2014

A small usability improvement to the new visual ListView designer available in v14.2

Thanks to our great customers and their feedback in this Support Center ticket we could make our recent addition to the Model Editor yet better. Starting with version 14.2.4, it will be much more convenient to view and configure ListView with lots of columns, because now the horizontal scrollbar will be displayed in this situation. A picture is worth a thousand words:


Of course, the live preview will also respect column sizes set in the property grid for each IModelColumn object.

What's New in XAF 14.2 Documentation

In addition to the new great features the version 14.2 introduced, there are also improvements to the learning materials that will allow you get the most of DevExpress products. 

The full list of What's New In Help for all products is waiting you here.
The XAF documentation changes are listed here. In particular, I wanted to focus on the restructured and improved Business Model Design section, which is, in my opinion, one of the most important things that contributes to overall understanding of the framework and its development process. 


My other favorite help topic is eXpressApp Framework > Concepts > UI Construction > List View Data Access Modes. Hopefully, even people familiar with the framework will find something helpful here. 


Friday, October 10, 2014

How to improve the application's performance

"Long time no see"...but I think that today's post will be added into favorites by many of you so it is worth a delay. We've collected typical mistakes in ORM data model design as well as general issues that may lead to performance problems and provided solutions and general recommendations in one place/KB article for you:


This collection covers the most popular scenarios and is based on what we have suggested in the Support Center database. If you have suggestions or questions, feel free to comment - we will be happy to make this troubleshooting guide yet more helpful.

BTW, a bit off-topic, but I have fixed a couple of small memory leaks in v.14.1.7 (related to delayed initialization of tabs and security), so you may want to install this hot fix build (or wait for v14.1.8+) to have more stability and less memory usage in XAF Web UI.

Happy speeding!;-)


Tuesday, September 9, 2014

Example of a custom PropertyEditor based on the ASPxColorEdit control

I wanted to share an example of a custom XAF Property Editor for viewing and editing System.Drawing.Color properties on the Web. This is what it looks like in the UI:


This custom PropertyEditor uses the built-in ASPxColorEdit control from our ASP.NET Suite and provides a bit better UX than the default ASPxColorPropertyEditor:

Sunday, August 17, 2014

Are you ready for some serious Xafari?

I am a bit late with this announcement, and you might have already been aware of the XAFARI.NET platform from our news feeds in developer groups, but here we go. 

If you do not recall my introduction blog post "Meet XAFARI - a business platform from Galaktika Corp", please refresh your memory first to learn more on this powerful business platform, which is built on top of eXpressApp Framework (XAF) to provide more reusable modules and components for various verticals.

The main reason for this post is that XAFARI got an English version of their website (it was only in Russian previously), which means that more XAFers could benefit from the numerous features this commercial third-party platform provides:



To learn more on pricing, features and services, including but not limited to access to the source code, online documentation, priority support, etc), check out http://galaktikasoft.com/xafari/buy (of course, free trial included):

Monday, August 11, 2014

Personalizing and securing the runtime Model Editor for your end-users


There is the word "tricks" in the name of my blog, and today I really want to tell you about something, which is in my opinion, deserves to be called a real trick. At least I am sure that I am going to highlight a solution, which not everyone is aware of and using in his production app. But, don't worry, because this solution is based on the well-tested core functionality of the framework and approach described in the XAF documentation: How to: Access Business Object Metadata.

Scenario

In the majority of customer projects I have seen, end-users are not using the runtime Model Editor, most likely because this developer tool can be confusing, and it is quite easy to "shoot yourself the foot" with it. This blog post is devoted to showing a way of customizing the Model Editor to limit end-users to see only certain nodes. For instance, one may want regular users to see only the Options and Validation nodes, while allowing full customization to administrators. Also, many may want to see a custom text within the Model Editor form header instead of the default XAF text.



Wednesday, August 6, 2014

Forcing Boolean Property Editor to work for a string DB column

The world is not perfect and sometimes we have to deal with legacy data, which is not well organized. For instance, data which is binary by nature can be stored using predefined strings ("T"/"F" or "Y"/"N"):


Correcting data is not often possible, because this data can already be used by other information systems.
As you know, XAF automatically generates editors for data fields in the UI based on the field type in the ORM data model (learn more...), so in this particular case an inappropriate editor (text box) will be used if we leave the default mapping to a string column "as is" - a text box instead of a check box or drop down box with the Yes/No values. In this blog post I will show you several methods on how to work around this situation and have the correct editor in the UI while keeping the underlying data table schema and data unchanged.

Wednesday, July 30, 2014

Checking if an object is new or not within a criterion string

Typical usage scenarios

I remember registering a corresponding feature request in order to make it easier for XAF developers to accomplish the following types of tasks:
a) Validating data fields for new records only; e.g., the scenario from Q440548
b) Implementing different data field appearance for new and saved records; e.g., the color or enabled state as in Q475272
c) Managing Action controls' state for new records via TargetObjectsCriteria

During these years these three scenarios stayed popular among our users (we had several dozens of trackers), so it was a natural decision for us, as framework creators, to make accomplishing this common and proven stuff easier for developers and probably end users.


Saturday, July 19, 2014

How to customize the underlying database provider options and data access behavior in XAF


I just wanted to repost my recent update to the corresponding article, because this information can interest some advanced XAF users.

IMPORTANT NOTE

This article describes some advanced customization techniques and low-level entities of the framework with regard to data access, which may be required in complex scenarios only.
So, if you just want to change the connection string, e.g. to use the Oracle instead of the Microsoft SQL Server database, then you would better refer to the Connect an XAF Application to a Database Provider article and documentation on your database provider instead. The XAF integration of supported ORM libraries is also described in the Business Model Design section of the framework's documentation.

Introducing IObjectSpaceProvider and IObjectSpace

XAF accesses data from a data store through special abstractions called - IObjectSpaceProvider and IObjectSpace.
The IObjectSpace is an abstraction above the ORM-specific database context (e.g., the DBContext used in Entity Framework or the Session in XPO) allowing you to query or modify data.
The IObjectSpaceProvider is a provider/creator of IObjectSpace entities, which also manages which business types these IObjectSpace are supposed to work with, how to set up the underlying connection to the database, create and update it and other low level data access options.



An XafApplication can use one or several IObjectSpaceProvider objects at the same time, and you can access this information through the XafApplication.ObjectSpaceProvder or XafApplication.ObjectSpaceProviders properties. Check out these help links to learn more on how to plug in custom IObjectSpaceProvider objects a well.

There are several built-in implementations of the IObjectSpaceProvider and IObjectSpace interfaces in our framework, which are usually specific to a target ORM (Entity Framework or XPO). I suggest you check out the source code of the default framework classes to better understand the role of the IObjectSpaceProvider:
...\DevExpress.ExpressApp.Xpo\XPObjectSpaceProvider.cs
...\DevExpress.ExpressApp.EF\EFObjectSpaceProvider.cs 

Display issue with the WinForms layout customization form in v14.1.5

Please beware of the 

We sincerely apologize for all the inconvenience here.

Monday, June 30, 2014

Using a built-in lookup editor based on values from another table for editing simple property types

This is actually a variation of a solution I described in my recent A very interesting way to update and display a persistent property via a non-persistent one post, because it is again based on a non-persistent reference property filtered using the DataSourcePropertyAttribute along with a custom data source collection.
This non-persistent reference property is represented using the standard XAF's lookup PropertyEditors, which are quite convenient for providing a user with the capability to select a single value either from a database table or from an arbitrary data source. In one turn, by adding custom logic to the getter and setter of our non-persistent calculated property, we can update the stored persistent value, which does not need to be a reference to another persistent class (table), but to any type (e.g., string or integer). This may come in handy for legacy databases when you cannot really modify the schema to provide normal associations between tables.



Let's take a look at the actual code for this solution:

Thursday, June 26, 2014

Сustomizing the number of failed login attempts before exiting the application with the enabled security system

Just wanted to inform you of another improvement, which you may find helpful.
From http://www.devexpress.com/Support/Center/Question/Details/S36898:


Implemented:
  • v2014 vol 1.5 : Official update is not yet available


Additional information:
The XafApplication class now provides the MaxLogonAttemptCount property, which is set to 3 by default. You can modify this default either in code or via the Application Designer.



I wanted to thank our customers Krzysztof and Robert for reminding us about this in the Support Center ticket. Please do not hesitate to contact us about similar gems that can improve your life as a framework developer. We are always happy to hear from you on what and how you develop, which scenarios are most important to you and what can be done to make it even better.

ViewController or Action activation for multiple Views or target object types via the TargetViewId property

I would like to highlight a small usability improvement that may help you write less and simpler code when configuring a target View for which a ViewController or an Action will be available.

Let's consider a couple scenarios where it may be helpful:
1. Your ViewController/Action should work for Views corresponding to absolutely unrelated Object1 and Object2 types (there is no inheritance between them and they are not descended from a common base class).
2. Your ViewController/Action should work for several specific Views of a certain object type, but be unavailable for other Views of the same type (e.g., be active for Object3_ListView, Object3_DetailView, but not for Object3_LookupListView and others).

Starting with version 14.1, you can implement the second scenario by setting the TargetViewId property of your ViewController or Action by providing a semicolon-separated list of Views, for which your element should be activated. Previously, you should have written the View.Id checks manually before executing your code. Please consider the following example:

Tuesday, June 3, 2014

Using a control that is not integrated by default

XAF is designed as a highly extensible and customizable framework. So, in most cases, the task of integrating a WinForms or an ASP.NET control is quite simple. You can integrate a DevExpress control that is not supported by default, a third-party control, or your own custom control. Generally, you should implement an abstract entity (ListEditor, PropertyEditor or ViewItem) that wraps the control and serves as an adapter for the XAF infrastructure. You can also customize a template and place the control in the desired location.

To help you choose an appropriate solution depending on your business scenario we have created a table that lists typical tasks and provides links to relevant examples:

https://help.devexpress.com/#Xaf/CustomDocument3610

I hope you find this new documentation helpful.


Tuesday, May 20, 2014

RE: WinForms Outlook-Style Navigation Controls (Coming soon in v14.1)

I am writing this post in response to the recent blog from our WinForms team: https://community.devexpress.com/blogs/thinking/archive/2014/05/09/winforms-outlook-style-navigation-controls-coming-soon-in-v14-1.aspx. There were a lot of comments on whether it is possible to have this feature in XAF. Well, it is possible and this integration is quite easy if you really need it. After all, an XAF app is nothing more than a standard WinForms or ASP.NET Web Forms app, which means that the same approaches can be applied to develop it. The XAF documentation describes most of the integration scenarios and our support team is also ready to help if you are in a need for something special.

Another good news is that here, it is all standard and you just need basic WinForms development skills and a minute or two to follow the How to: Customize a Windows Forms Template article from the XAF's documentation.


Caution: I was not planning on replicating Outlook 2013 by any means here, but just experimented with alternative navigation controls. I also removed the status bar, placed the navigation bar under the main view site and did not use tree-like navigation in groups on purpose, because it was not very suitable just for this simple demo app. Replicating the Office 2013 UI requires additional customizations of templates and other UI elements, and is not covered in this post.

Wednesday, May 14, 2014

A very interesting way to update and display a persistent property via a non-persistent one

Scenario:

A customer wanted to extend the User class with additional property that would store the information about the startup View for this user when it launches the app. This is very similar to the StartupNavigationItem attribute, which is present for the NavigationItems node in the application model, but with the difference that application users should be able to modify this via the standard XAF CRUD forms.

How would you normally approach this?;-)

Possible solutions

At this time, I can think of at least three good options for accomplishing this task: two platform-dependent and one platform-agnostic, which I am going to detail later in this post. In all three cases we will extend our business class with a string property that would store this startup View information (its identifier) in the database.

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

http://habrahabr.ru/company/devexpress/blog/211805/

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:

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

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

!!!The contents of this article were moved to www.devexpress.com/issue=KA18895!!!

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:

   Frame
      • 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:

   View
       • CompositeView
              • DashboardView
              • ObjectView
                     • DetailView
                     • ListView


There are also several built-in ViewItem types:

   ViewItem
       • 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() {
            base.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() {
            base.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;
                    //Or                    
                    DashboardView containerView2 = (DashboardView)dashboardViewItem.View;
                    //Example #9                    
                    ViewItem nestedFrameViewItem = nestedFrame.ViewItem;
                };
            }
        }
    }
}


See Also