(I have spent some time figuring this one myself, so I hope it will be of use to someone...)
When creating a UserControl, doesn't matter if it's System.Windows.Forms.UserControl or DevExpress.XtraEditors.XtraUserControl a problem occurs when a data source (XPView, XPCollection, UnitOfWork or anything else that requires a session) is placed on a control and then the control is used in a form
The problem boils down to:
Data sources use a session, which, if not set, will be set to default (Session.DefaultSession).
Sessions in your app are created at runtime (at login or on-the-fly)
Finished UserControl when placed on a form is not in design mode -> Visual Studio Win Forms designer actively executes constructor and event handling routines of child controls
This will cause an exception when adding control to the form or designer will issue warning. The warning message is typically something along the lines of "C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\DefaultDomain.mdb"
cannot be found or is inaccessible. This is the Access database used by default session.
As a solution, you can reimplement the DesignMode property and distinguish between code running in the designer or at runtime.
Base implementation of DesignMode cannot really be used to determine this. The recommended method is to check whether code being run is executed in VS, that means checking if the current process is "devenv.exe".
public new bool DesignMode
{
get
{
// check base implementation as well
return ((base.DesignMode) ||
(Process.GetCurrentProcess().ProcessName.ToLowerInvariant() == "devenv"));
}
}
(There are other methods as well, such as checking the licensing mode which is VS specific, but I prefer this one)
It is then possible to rip out the code from InitializeComponent which instantiates and initializes data sources and place it behind a conditional, which will only be run if the control is outside the VS designer.
internal class Order : XPObject
{
...
public Order(int someArg)
{
InitializeComponent();
if (!this.DesignMode)
{
// xpCollection1 init
this.xpCollection1 = new UnisComp.Pry.Spol.Base.BL.BusinessCollectionBase();
((System.ComponentModel.ISupportInitialize)(this.xpCollection1)).BeginInit();
this.xpCollection1.LoadingEnabled = false;
this.xpCollection1.ObjectType = typeof(Category);
((System.ComponentModel.ISupportInitialize)(this.xpCollection1)).EndInit();
}
}
...
}
Things to consider:
VS designer is runtime. It will execute code for child controls and I mean any method which is in constructor call chain or any event handler that reacts to events which are raised by the designer. The parent form or control which is being designed is merely serialized so no problem there.
- Events raised by the designer include control's Load event, so that's no place for initialization either.
- This behaviour is by design and will not be changed. Developers are encouraged to work around this
(see Bug Report Details: DefaultDomain.mdb (DevExpress), Bug Report Details: Form can't be open in the designer and throws an exception about DefaultDomain.mdb (DevExpress) and DesignMode property not telling the full truth (.NET)