| File: System\ComponentModel\Design\DesignSurfaceManager.cs | Web Access |
| Project: src\winforms\src\System.Windows.Forms.Design\src\System.Windows.Forms.Design.csproj (System.Windows.Forms.Design) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. namespace System.ComponentModel.Design; /// <summary> /// A service container that supports "fixed" services. Fixed /// services cannot be removed. /// </summary> public class DesignSurfaceManager : IServiceProvider, IDisposable { private readonly IServiceProvider? _parentProvider; private ServiceContainer? _serviceContainer; private ActiveDesignSurfaceChangedEventHandler? _activeDesignSurfaceChanged; private DesignSurfaceEventHandler? _designSurfaceCreated; private DesignSurfaceEventHandler? _designSurfaceDisposed; private EventHandler? _selectionChanged; /// <summary> /// Creates a new designer application. /// </summary> public DesignSurfaceManager() : this(null) { } /// <summary> /// Creates a new designer application and provides a /// parent service provider. /// </summary> public DesignSurfaceManager(IServiceProvider? parentProvider) { _parentProvider = parentProvider; ServiceCreatorCallback callback = new(OnCreateService); ServiceContainer.AddService<IDesignerEventService>(callback); } /// <summary> /// This property should be set by the designer's user interface /// whenever a designer becomes the active window. The default /// implementation of this property works with the default /// implementation of IDesignerEventService to notify interested /// parties that a new designer is now active. If you provide /// your own implementation of IDesignerEventService you should /// override this property to notify your service appropriately. /// </summary> public virtual DesignSurface? ActiveDesignSurface { get => EventService?.ActiveDesigner?.GetService<DesignSurface>(); set { // If we are providing IDesignerEventService, then we are responsible for // notifying it of new designers coming into place. If we aren't // the ones providing the event service, then whoever is providing // it will be responsible for updating it when new designers // are created. if (EventService is DesignerEventService eventService) { eventService.OnActivateDesigner(value); } } } /// <summary> /// A collection of design surfaces. This is offered /// for convience, and simply maps to IDesignerEventService. /// </summary> public DesignSurfaceCollection DesignSurfaces => new(EventService?.Designers); /// <summary> /// We access this a lot. /// </summary> private IDesignerEventService? EventService => GetService(typeof(IDesignerEventService)) as IDesignerEventService; /// <summary> /// Provides access to the designer application's /// ServiceContainer. This property allows /// inheritors to add their own services. /// </summary> protected ServiceContainer ServiceContainer => _serviceContainer ??= new ServiceContainer(_parentProvider); /// <summary> /// This event is raised when a new design surface gains /// activation. This is mapped through IDesignerEventService. /// </summary> public event ActiveDesignSurfaceChangedEventHandler? ActiveDesignSurfaceChanged { add { if (_activeDesignSurfaceChanged is null) { IDesignerEventService? eventService = EventService; eventService?.ActiveDesignerChanged += OnActiveDesignerChanged; } _activeDesignSurfaceChanged += value; } remove { _activeDesignSurfaceChanged -= value; if (_activeDesignSurfaceChanged is not null) { return; } IDesignerEventService? eventService = EventService; eventService?.ActiveDesignerChanged -= OnActiveDesignerChanged; } } /// <summary> /// This event is raised when a new design surface is /// created. This is mapped through IDesignerEventService. /// </summary> public event DesignSurfaceEventHandler? DesignSurfaceCreated { add { if (_designSurfaceCreated is null) { IDesignerEventService? eventService = EventService; eventService?.DesignerCreated += OnDesignerCreated; } _designSurfaceCreated += value; } remove { _designSurfaceCreated -= value; if (_designSurfaceCreated is not null) { return; } IDesignerEventService? eventService = EventService; eventService?.DesignerCreated -= OnDesignerCreated; } } /// <summary> /// This event is raised when a design surface is disposed. /// This is mapped through IDesignerEventService. /// </summary> public event DesignSurfaceEventHandler? DesignSurfaceDisposed { add { if (_designSurfaceDisposed is null) { IDesignerEventService? eventService = EventService; eventService?.DesignerDisposed += OnDesignerDisposed; } _designSurfaceDisposed += value; } remove { _designSurfaceDisposed -= value; if (_designSurfaceDisposed is not null) { return; } IDesignerEventService? eventService = EventService; eventService?.DesignerDisposed -= OnDesignerDisposed; } } /// <summary> /// This event is raised when the active designer's /// selection of component set changes. This is mapped /// through IDesignerEventService. /// </summary> public event EventHandler? SelectionChanged { add { if (_selectionChanged is null) { IDesignerEventService? eventService = EventService; eventService?.SelectionChanged += OnSelectionChanged; } _selectionChanged += value; } remove { _selectionChanged -= value; if (_selectionChanged is not null) { return; } IDesignerEventService? eventService = EventService; eventService?.SelectionChanged -= OnSelectionChanged; } } /// <summary> /// Public method to create a design surface. /// </summary> public DesignSurface CreateDesignSurface() { DesignSurface surface = CreateDesignSurfaceCore(this); // If we are providing IDesignerEventService, then we are responsible for // notifying it of new designers coming into place. If we aren't // the ones providing the event service, then whoever is providing // it will be responsible for updating it when new designers are created. if (GetService(typeof(IDesignerEventService)) is DesignerEventService eventService) { eventService.OnCreateDesigner(surface); } return surface; } /// <summary> /// Public method to create a design surface. This method /// takes an additional service provider. This service /// provider will be combined with the service provider /// already contained within DesignSurfaceManager. Service /// requests will go to this provider first, and then bubble /// up to the service provider owned by DesignSurfaceManager. /// This allows for services to be tailored for each design surface. /// </summary> public DesignSurface CreateDesignSurface(IServiceProvider parentProvider) { ArgumentNullException.ThrowIfNull(parentProvider); IServiceProvider mergedProvider = new MergedServiceProvider(parentProvider, this); DesignSurface surface = CreateDesignSurfaceCore(mergedProvider); // If we are providing IDesignerEventService, then we are responsible for // notifying it of new designers coming into place. If we aren't // the ones providing the event service, then whoever is providing // it will be responsible for updating it when new designers are created. DesignerEventService? eventService = GetService(typeof(IDesignerEventService)) as DesignerEventService; eventService?.OnCreateDesigner(surface); return surface; } /// <summary> /// Creates an instance of a design surface. This can be /// overridden to provide a derived version of DesignSurface. /// </summary> protected virtual DesignSurface CreateDesignSurfaceCore(IServiceProvider parentProvider) => new(parentProvider); /// <summary> /// Disposes the designer application. /// </summary> public void Dispose() { Dispose(true); } /// <summary> /// Protected override of Dispose that allows for cleanup. /// </summary> protected virtual void Dispose(bool disposing) { if (!disposing || _serviceContainer is null) { return; } _serviceContainer.Dispose(); _serviceContainer = null; } /// <summary> /// Retrieves a service in this design surface's service /// container. /// </summary> public object? GetService(Type serviceType) => _serviceContainer?.GetService(serviceType); /// <summary> /// Private method that demand-creates services we offer. /// </summary> /// <param name="container"> /// The service container requesting the service. /// </param> /// <param name="serviceType"> /// The type of service being requested. /// </param> /// <returns> /// A new instance of the service. It is an error to call this with /// a service type it doesn't know how to create /// </returns> private static object? OnCreateService(IServiceContainer container, Type serviceType) { if (serviceType == typeof(IDesignerEventService)) { return new DesignerEventService(); } Debug.Fail($"Demand created service not supported: {serviceType.Name}"); return null; } /// <summary> /// Handles the IDesignerEventService event and relays it to /// DesignSurfaceManager's similar event. /// </summary> private void OnActiveDesignerChanged(object? sender, ActiveDesignerEventArgs e) { Debug.Assert(_activeDesignSurfaceChanged is not null, "Should have detached this event handler."); if (_activeDesignSurfaceChanged is not null) { DesignSurface? oldSurface = e.OldDesigner?.GetService<DesignSurface>(); DesignSurface? newSurface = e.NewDesigner?.GetService<DesignSurface>(); _activeDesignSurfaceChanged(this, new ActiveDesignSurfaceChangedEventArgs(oldSurface, newSurface)); } } /// <summary> /// Handles the IDesignerEventService event and relays it to /// DesignSurfaceManager's similar event. /// </summary> private void OnDesignerCreated(object? sender, DesignerEventArgs e) { Debug.Assert(_designSurfaceCreated is not null, "Should have detached this event handler."); if (_designSurfaceCreated is null) { return; } if (e.Designer!.GetService(typeof(DesignSurface)) is DesignSurface surface) { _designSurfaceCreated(this, new DesignSurfaceEventArgs(surface)); } } /// <summary> /// Handles the IDesignerEventService event and relays it to /// DesignSurfaceManager's similar event. /// </summary> private void OnDesignerDisposed(object? sender, DesignerEventArgs e) { Debug.Assert(_designSurfaceDisposed is not null, "Should have detached this event handler."); if (_designSurfaceDisposed is null) { return; } if (e.Designer!.GetService(typeof(DesignSurface)) is DesignSurface surface) { _designSurfaceDisposed(this, new DesignSurfaceEventArgs(surface)); } } /// <summary> /// Handles the IDesignerEventService event and relays it to /// DesignSurfaceManager's similar event. /// </summary> private void OnSelectionChanged(object? sender, EventArgs e) { Debug.Assert(_selectionChanged is not null, "Should have detached this event handler."); _selectionChanged?.Invoke(this, e); } /// <summary> /// Simple service provider that merges two providers together. /// </summary> private sealed class MergedServiceProvider : IServiceProvider { private readonly IServiceProvider _primaryProvider; private readonly IServiceProvider _secondaryProvider; internal MergedServiceProvider(IServiceProvider primaryProvider, IServiceProvider secondaryProvider) { _primaryProvider = primaryProvider; _secondaryProvider = secondaryProvider; } object? IServiceProvider.GetService(Type serviceType) { ArgumentNullException.ThrowIfNull(serviceType); object? service = _primaryProvider.GetService(serviceType); service ??= _secondaryProvider.GetService(serviceType); return service; } } }