3c1f479b9d
Former-commit-id: 806294f5ded97629b74c85c09952f2a74fe182d9
396 lines
11 KiB
C#
396 lines
11 KiB
C#
//
|
|
// System.ComponentModel.Design.Serialization.BasicDesignerLoader
|
|
//
|
|
// Authors:
|
|
// Ivan N. Zlatev (contact i-nZ.net)
|
|
//
|
|
// (C) 2007 Ivan N. Zlatev
|
|
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining
|
|
// a copy of this software and associated documentation files (the
|
|
// "Software"), to deal in the Software without restriction, including
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
|
// permit persons to whom the Software is furnished to do so, subject to
|
|
// the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be
|
|
// included in all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
//
|
|
|
|
|
|
using System;
|
|
using System.Collections;
|
|
using System.ComponentModel;
|
|
using System.ComponentModel.Design;
|
|
using System.Windows.Forms;
|
|
|
|
namespace System.ComponentModel.Design.Serialization
|
|
{
|
|
public abstract class BasicDesignerLoader : DesignerLoader, IDesignerLoaderService
|
|
{
|
|
|
|
[Flags]
|
|
protected enum ReloadOptions
|
|
{
|
|
Default,
|
|
Force,
|
|
ModifyOnError,
|
|
NoFlush
|
|
}
|
|
|
|
private bool _loaded;
|
|
private bool _loading;
|
|
private IDesignerLoaderHost _host;
|
|
private int _dependenciesCount;
|
|
private bool _notificationsEnabled;
|
|
private bool _modified;
|
|
private string _baseComponentClassName;
|
|
private DesignerSerializationManager _serializationMananger;
|
|
private bool _flushing;
|
|
private bool _reloadScheduled;
|
|
private ReloadOptions _reloadOptions;
|
|
|
|
protected BasicDesignerLoader ()
|
|
{
|
|
_loading = _loaded = _flushing = _reloadScheduled = false;
|
|
_host = null;
|
|
_notificationsEnabled = false;
|
|
_modified = false;
|
|
_dependenciesCount = 0;
|
|
}
|
|
|
|
protected virtual void Initialize ()
|
|
{
|
|
_serializationMananger = new DesignerSerializationManager (_host);
|
|
|
|
DesignSurfaceServiceContainer serviceContainer = _host.GetService (typeof (IServiceContainer)) as DesignSurfaceServiceContainer;
|
|
if (serviceContainer != null) {
|
|
serviceContainer.AddService (typeof (IDesignerLoaderService), (IDesignerLoaderService) this);
|
|
serviceContainer.AddNonReplaceableService (typeof (IDesignerSerializationManager), _serializationMananger);
|
|
}
|
|
}
|
|
|
|
public override void BeginLoad (IDesignerLoaderHost host)
|
|
{
|
|
if (host == null)
|
|
throw new ArgumentNullException ("host");
|
|
if (_loaded)
|
|
throw new InvalidOperationException ("Already loaded.");
|
|
if (_host != null && _host != host)
|
|
throw new InvalidOperationException ("Trying to load with a different host");
|
|
|
|
if (_host == null) { // beingload is called on reload - no need to initialize twice.
|
|
_host = host;
|
|
Initialize ();
|
|
}
|
|
IDisposable session = _serializationMananger.CreateSession ();
|
|
|
|
IDesignerLoaderService loader = _host.GetService (typeof (IDesignerLoaderService)) as IDesignerLoaderService;
|
|
|
|
if (loader != null) {
|
|
_dependenciesCount = -1;
|
|
loader.AddLoadDependency ();
|
|
} else {
|
|
OnBeginLoad ();
|
|
}
|
|
|
|
bool successful = true;
|
|
|
|
try {
|
|
PerformLoad (_serializationMananger);
|
|
} catch (Exception e) {
|
|
successful = false;
|
|
_serializationMananger.Errors.Add (e);
|
|
}
|
|
|
|
if (loader != null)
|
|
loader.DependentLoadComplete (successful, _serializationMananger.Errors);
|
|
else
|
|
OnEndLoad (successful, _serializationMananger.Errors);
|
|
|
|
session.Dispose ();
|
|
}
|
|
|
|
protected abstract void PerformLoad (IDesignerSerializationManager serializationManager);
|
|
|
|
protected virtual void OnBeginLoad ()
|
|
{
|
|
_loading = true;
|
|
}
|
|
|
|
protected virtual void OnEndLoad (bool successful, ICollection errors)
|
|
{
|
|
_host.EndLoad (_baseComponentClassName, successful, errors);
|
|
|
|
if (successful) {
|
|
_loaded = true;
|
|
EnableComponentNotification (true);
|
|
} else {
|
|
if (_reloadScheduled) { // we are reloading
|
|
bool modify = ((_reloadOptions & ReloadOptions.ModifyOnError) == ReloadOptions.ModifyOnError);
|
|
if (modify) {
|
|
OnModifying ();
|
|
this.Modified = true;
|
|
}
|
|
}
|
|
}
|
|
_loading = false;
|
|
}
|
|
|
|
public override bool Loading {
|
|
get { return _loading; }
|
|
}
|
|
|
|
protected IDesignerLoaderHost LoaderHost {
|
|
get { return _host; }
|
|
}
|
|
|
|
protected virtual bool Modified {
|
|
get { return _modified; }
|
|
set { _modified = value; }
|
|
}
|
|
|
|
protected object PropertyProvider {
|
|
get {
|
|
if (!_loaded)
|
|
throw new InvalidOperationException ("host not initialized");
|
|
return _serializationMananger.PropertyProvider;
|
|
}
|
|
set {
|
|
if (!_loaded)
|
|
throw new InvalidOperationException ("host not initialized");
|
|
_serializationMananger.PropertyProvider = value;
|
|
}
|
|
}
|
|
|
|
protected bool ReloadPending {
|
|
get { return _reloadScheduled; }
|
|
}
|
|
|
|
protected virtual bool EnableComponentNotification (bool enable)
|
|
{
|
|
if (!_loaded)
|
|
throw new InvalidOperationException ("host not initialized");
|
|
|
|
IComponentChangeService service = _host.GetService (typeof (IComponentChangeService)) as IComponentChangeService;
|
|
if (service != null && _notificationsEnabled != enable) {
|
|
if (enable) {
|
|
service.ComponentAdding += new ComponentEventHandler (OnComponentAdding);
|
|
service.ComponentAdded += new ComponentEventHandler (OnComponentAdded);
|
|
service.ComponentRemoving += new ComponentEventHandler (OnComponentRemoving);
|
|
service.ComponentRemoved += new ComponentEventHandler (OnComponentRemoved);
|
|
service.ComponentChanging += new ComponentChangingEventHandler (OnComponentChanging);
|
|
service.ComponentChanged += new ComponentChangedEventHandler (OnComponentChanged);
|
|
service.ComponentRename += new ComponentRenameEventHandler (OnComponentRename);
|
|
} else {
|
|
service.ComponentAdding -= new ComponentEventHandler (OnComponentAdding);
|
|
service.ComponentAdded -= new ComponentEventHandler (OnComponentAdded);
|
|
service.ComponentRemoving -= new ComponentEventHandler (OnComponentRemoving);
|
|
service.ComponentRemoved -= new ComponentEventHandler (OnComponentRemoved);
|
|
service.ComponentChanging -= new ComponentChangingEventHandler (OnComponentChanging);
|
|
service.ComponentChanged -= new ComponentChangedEventHandler (OnComponentChanged);
|
|
service.ComponentRename -= new ComponentRenameEventHandler (OnComponentRename);
|
|
}
|
|
}
|
|
return _notificationsEnabled == true ? true : false;
|
|
}
|
|
|
|
private void OnComponentAdded (object sender, ComponentEventArgs args)
|
|
{
|
|
if (!_loading && _loaded)
|
|
this.Modified = true;
|
|
}
|
|
|
|
private void OnComponentRemoved (object sender, ComponentEventArgs args)
|
|
{
|
|
if (!_loading && _loaded)
|
|
this.Modified = true;
|
|
}
|
|
|
|
private void OnComponentAdding (object sender, ComponentEventArgs args)
|
|
{
|
|
if (!_loading && _loaded)
|
|
OnModifying ();
|
|
}
|
|
|
|
private void OnComponentRemoving (object sender, ComponentEventArgs args)
|
|
{
|
|
if (!_loading && _loaded)
|
|
OnModifying ();
|
|
}
|
|
|
|
private void OnComponentChanged (object sender, ComponentChangedEventArgs args)
|
|
{
|
|
if (!_loading && _loaded)
|
|
this.Modified = true;
|
|
}
|
|
|
|
private void OnComponentChanging (object sender, ComponentChangingEventArgs args)
|
|
{
|
|
if (!_loading && _loaded)
|
|
OnModifying ();
|
|
}
|
|
|
|
private void OnComponentRename (object sender, ComponentRenameEventArgs args)
|
|
{
|
|
if (!_loading && _loaded) {
|
|
OnModifying ();
|
|
this.Modified = true;
|
|
}
|
|
}
|
|
|
|
public override void Flush ()
|
|
{
|
|
if (!_loaded)
|
|
throw new InvalidOperationException ("host not initialized");
|
|
|
|
if (!_flushing && this.Modified) {
|
|
_flushing = true;
|
|
using ((IDisposable)_serializationMananger.CreateSession ()) {
|
|
try {
|
|
PerformFlush (_serializationMananger);
|
|
} catch (Exception e) {
|
|
_serializationMananger.Errors.Add (e);
|
|
ReportFlushErrors (_serializationMananger.Errors);
|
|
}
|
|
}
|
|
_flushing = false;
|
|
}
|
|
}
|
|
|
|
protected abstract void PerformFlush (IDesignerSerializationManager serializationManager);
|
|
|
|
// MSDN: The default implementation always returns true.
|
|
protected virtual bool IsReloadNeeded ()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
|
|
protected virtual void OnBeginUnload ()
|
|
{
|
|
}
|
|
|
|
protected virtual void OnModifying ()
|
|
{
|
|
}
|
|
|
|
// MSDN: reloads are performed at idle time
|
|
protected void Reload (ReloadOptions flags)
|
|
{
|
|
if (!_reloadScheduled) {
|
|
_reloadScheduled = true;
|
|
_reloadOptions = flags;
|
|
bool force = ((flags & ReloadOptions.Force) == ReloadOptions.Force);
|
|
if (force)
|
|
ReloadCore ();
|
|
else
|
|
Application.Idle += new EventHandler (OnIdle);
|
|
}
|
|
}
|
|
|
|
private void OnIdle (object sender, EventArgs args)
|
|
{
|
|
Application.Idle -= new EventHandler (OnIdle);
|
|
ReloadCore ();
|
|
}
|
|
|
|
private void ReloadCore ()
|
|
{
|
|
bool flush = !((_reloadOptions & ReloadOptions.NoFlush) == ReloadOptions.NoFlush);
|
|
|
|
if (flush)
|
|
Flush ();
|
|
Unload ();
|
|
_host.Reload ();
|
|
BeginLoad (_host); // calls EndLoad, which will check for ReloadOptions.ModifyOnError
|
|
_reloadScheduled = false;
|
|
}
|
|
|
|
private void Unload ()
|
|
{
|
|
if (_loaded) {
|
|
OnBeginUnload ();
|
|
EnableComponentNotification (false);
|
|
_loaded = false;
|
|
_baseComponentClassName = null;
|
|
}
|
|
}
|
|
|
|
|
|
// The default implementation of ReportFlushErrors raises the last exception in the collection.
|
|
//
|
|
protected virtual void ReportFlushErrors (ICollection errors)
|
|
{
|
|
object last = null;
|
|
foreach (object o in errors)
|
|
last = o;
|
|
throw (Exception)last;
|
|
}
|
|
|
|
// Must be called during PerformLoad by subclasses.
|
|
protected void SetBaseComponentClassName (string name)
|
|
{
|
|
if (name == null)
|
|
throw new ArgumentNullException ("name");
|
|
_baseComponentClassName = name;
|
|
}
|
|
|
|
#region IDesignerLoaderService implementation
|
|
|
|
void IDesignerLoaderService.AddLoadDependency ()
|
|
{
|
|
_dependenciesCount++;
|
|
if (_dependenciesCount == 0) {
|
|
_dependenciesCount = 1;
|
|
OnBeginLoad ();
|
|
}
|
|
}
|
|
|
|
void IDesignerLoaderService.DependentLoadComplete (bool successful, ICollection errorCollection)
|
|
{
|
|
if (_dependenciesCount == 0)
|
|
throw new InvalidOperationException ("dependencies == 0");
|
|
|
|
_dependenciesCount--;
|
|
if (_dependenciesCount == 0) {
|
|
OnEndLoad (successful, errorCollection);
|
|
}
|
|
}
|
|
|
|
bool IDesignerLoaderService.Reload ()
|
|
{
|
|
if (_dependenciesCount == 0) {
|
|
this.Reload (ReloadOptions.Force);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
#endregion
|
|
|
|
protected object GetService (Type serviceType)
|
|
{
|
|
if (_host != null)
|
|
return _host.GetService (serviceType);
|
|
return null;
|
|
}
|
|
|
|
public override void Dispose ()
|
|
{
|
|
this.LoaderHost.RemoveService (typeof (IDesignerLoaderService));
|
|
Unload ();
|
|
}
|
|
}
|
|
}
|
|
|