2023-09-24 17:26:46 -04:00
using System.Collections ;
2017-11-27 13:11:20 -05:00
using System.Collections.Generic ;
using System.ComponentModel ;
using System.ComponentModel.Design ;
2023-09-29 13:58:35 -04:00
using System.Diagnostics.CodeAnalysis ;
2017-11-27 13:11:20 -05:00
using System.Drawing.Design ;
2018-01-12 13:41:42 -05:00
using System.Linq ;
2017-11-27 13:11:20 -05:00
using System.Reflection ;
using System.Windows.Forms ;
using System.Windows.Forms.Design ;
using System.Windows.Forms.Design.Behavior ;
2023-03-31 11:47:53 -04:00
namespace Vanara.Windows.Forms.Design ;
/// <summary>Interface for an action that has items and a category.</summary>
public interface IActionGetItem
{
/// <summary>Gets the category.</summary>
/// <value>The category.</value>
2023-09-29 13:58:35 -04:00
string? Category { get ; }
2023-03-31 11:47:53 -04:00
/// <summary>Gets the item.</summary>
/// <param name="actions">The actions.</param>
/// <param name="mbr">The MBR.</param>
/// <returns></returns>
2023-09-29 13:58:35 -04:00
DesignerActionItem GetItem ( DesignerActionList actions , MemberInfo mbr ) ;
2023-03-31 11:47:53 -04:00
}
/// <summary>Methods to assist when using designer code.</summary>
public static class ComponentDesignerExtension
2017-11-27 13:11:20 -05:00
{
2023-03-31 11:47:53 -04:00
/// <summary>Launches the design-time editor for the property of the component behind a designer.</summary>
/// <param name="designer">The designer for a component.</param>
/// <param name="propName">The name of the property to edit. If this value is null, the default property for the object is used.</param>
/// <param name="objectToChange">
/// The object on which to edit the property. If this value is null, the Component property of the designer is used.
/// </param>
/// <returns>The new value returned by the editor.</returns>
2023-09-29 13:58:35 -04:00
public static object? EditValue ( this ComponentDesigner designer , string propName , object? objectToChange = null )
2020-04-02 23:59:18 -04:00
{
2023-09-29 13:58:35 -04:00
objectToChange ? ? = designer . Component ;
2023-03-31 11:47:53 -04:00
var prop = ( ( propName = = null ) ? TypeDescriptor . GetDefaultProperty ( objectToChange ) : TypeDescriptor . GetProperties ( objectToChange ) [ propName ] ) ? ? throw new ArgumentException ( "Unable to retrieve specified property." ) ;
var context = new EditorServiceContext ( designer , prop ) ;
var editor = prop . GetEditor ( typeof ( UITypeEditor ) ) as UITypeEditor ;
var curVal = prop . GetValue ( objectToChange ) ;
var newVal = editor ? . EditValue ( context , context , curVal ) ;
if ( newVal ! = curVal )
try { prop . SetValue ( objectToChange , newVal ) ; }
catch ( CheckoutException ) { }
return newVal ;
2020-04-02 23:59:18 -04:00
}
2023-03-31 11:47:53 -04:00
/// <summary>Sets a property on the component behind a designer.</summary>
/// <typeparam name="T">The type of the property value.</typeparam>
/// <param name="d">The designer for a component.</param>
/// <param name="propName">
/// The name of the property to set. If this value is null, the default property for the object is used. This method will not set
/// the property if the property type does not match <typeparamref name="T"/>, if the property is read-only, or if the property is
/// not browsable.
/// </param>
/// <param name="value">The value to assign to the property.</param>
public static void SetComponentProperty < T > ( this ComponentDesigner d , string propName , T value )
2017-11-27 13:11:20 -05:00
{
2023-03-31 11:47:53 -04:00
var propDesc = ( propName = = null ) ? TypeDescriptor . GetDefaultProperty ( d . Component ) : TypeDescriptor . GetProperties ( d . Component ) [ propName ] ;
if ( propDesc ! = null & & propDesc . PropertyType = = typeof ( T ) & & ! propDesc . IsReadOnly & & propDesc . IsBrowsable )
propDesc . SetValue ( d . Component , value ) ;
2017-11-27 13:11:20 -05:00
}
2023-03-31 11:47:53 -04:00
/// <summary>Shows a form tied to a designer.</summary>
/// <param name="designer">The designer for a component.</param>
/// <param name="dialog">A form instance.</param>
/// <returns>The result of calling ShowDialog on the form.</returns>
public static DialogResult ShowDialog ( this ComponentDesigner designer , Form dialog )
2017-11-27 13:11:20 -05:00
{
2023-03-31 11:47:53 -04:00
var context = new EditorServiceContext ( designer ) ;
return context . ShowDialog ( dialog ) ;
2017-11-27 13:11:20 -05:00
}
2023-03-31 11:47:53 -04:00
}
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Extension methods for IServiceProvider.</summary>
public static partial class ServiceProviderExtension
{
/// <summary>Gets the service.</summary>
/// <typeparam name="T"></typeparam>
/// <param name="sp">The sp.</param>
/// <returns></returns>
2023-09-29 13:58:35 -04:00
public static T ? GetService < T > ( this IServiceProvider sp ) where T : class = > ( T ? ) sp . GetService ( typeof ( T ) ) ;
2023-03-31 11:47:53 -04:00
}
/// <summary>A designer for components that support attributes.</summary>
/// <typeparam name="TComponent">The type of the component.</typeparam>
2023-09-29 13:58:35 -04:00
/// <seealso cref="ComponentDesigner"/>
2023-03-31 11:47:53 -04:00
public abstract class AttributedComponentDesigner < TComponent > : ComponentDesigner where TComponent : Component
{
2023-09-29 13:58:35 -04:00
private readonly IDictionary < string , List < Attribute > > ? redirectedProps ;
private readonly DesignerVerbCollection ? verbs ;
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Initializes a new instance of the <see cref="AttributedComponentDesigner{TComponent}"/> class.</summary>
public AttributedComponentDesigner ( )
{
redirectedProps = this . GetRedirectedProperties ( ) ;
verbs = this . GetAttributedVerbs ( ) ;
}
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the design-time verbs supported by the component that is associated with the designer.</summary>
2023-09-29 13:58:35 -04:00
public override DesignerVerbCollection ? Verbs = > verbs ;
2020-04-02 23:59:18 -04:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the design-time action lists supported by the component associated with the designer.</summary>
public override DesignerActionListCollection ActionLists = >
this . GetActionLists ( Component , Actions , base . ActionLists , Verbs ) ;
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the component this designer is designing.</summary>
public new TComponent Component = > ( TComponent ) base . Component ;
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the actions.</summary>
/// <value>The actions.</value>
2023-09-29 13:58:35 -04:00
protected virtual AttributedDesignerActionList ? Actions = > null ;
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the properties to remove.</summary>
/// <value>The properties to remove.</value>
2023-09-29 13:58:35 -04:00
protected virtual IEnumerable < string > ? PropertiesToRemove = > null ;
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Allows a designer to add to the set of properties that it exposes through a <see cref="T:System.ComponentModel.TypeDescriptor"/>.</summary>
/// <param name="properties">The properties for the class of the component.</param>
protected override void PreFilterProperties ( IDictionary properties )
{
base . PreFilterProperties ( properties ) ;
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
if ( redirectedProps ! = null )
this . RedirectRegisteredProperties ( properties , redirectedProps ) ;
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
if ( PropertiesToRemove ! = null )
this . RemoveItems ( properties , PropertiesToRemove ) ;
2017-11-27 13:11:20 -05:00
}
2023-03-31 11:47:53 -04:00
}
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>An extended designer for components that support attributes.</summary>
/// <typeparam name="TComponent">The type of the component.</typeparam>
2023-09-29 13:58:35 -04:00
/// <seealso cref="ComponentDesigner"/>
2023-03-31 11:47:53 -04:00
public abstract class AttributedComponentDesignerEx < TComponent > : AttributedComponentDesigner < TComponent >
where TComponent : Component
{
2023-09-29 13:58:35 -04:00
private Adorner ? adorner ;
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the behavior service.</summary>
/// <value>The behavior service.</value>
2023-09-29 13:58:35 -04:00
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
2023-03-31 11:47:53 -04:00
public BehaviorService BehaviorService { get ; private set ; }
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the component change service.</summary>
/// <value>The component change service.</value>
public IComponentChangeService ComponentChangeService { get ; private set ; }
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the selection service.</summary>
/// <value>The selection service.</value>
public ISelectionService SelectionService { get ; private set ; }
2023-09-29 13:58:35 -04:00
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the glyphs.</summary>
/// <value>The glyphs.</value>
public virtual GlyphCollection Glyphs = > Adorner . Glyphs ;
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
internal Adorner Adorner
{
get
2017-11-27 13:11:20 -05:00
{
2023-03-31 11:47:53 -04:00
if ( adorner = = null )
BehaviorService . Adorners . Add ( adorner = new Adorner ( ) ) ;
return adorner ;
2017-11-27 13:11:20 -05:00
}
2023-03-31 11:47:53 -04:00
}
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Prepares the designer to view, edit, and design the specified component.</summary>
/// <param name="component">The component for this designer.</param>
public override void Initialize ( IComponent component )
{
base . Initialize ( component ) ;
BehaviorService = GetService < BehaviorService > ( ) ;
SelectionService = GetService < ISelectionService > ( ) ;
2023-09-29 13:58:35 -04:00
SelectionService . SelectionChanged + = OnSelectionChanged ;
2023-03-31 11:47:53 -04:00
ComponentChangeService = GetService < IComponentChangeService > ( ) ;
2023-09-29 13:58:35 -04:00
ComponentChangeService . ComponentChanged + = OnComponentChanged ;
2023-03-31 11:47:53 -04:00
}
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>
/// Releases the unmanaged resources used by the <see cref="T:System.ComponentModel.Design.ComponentDesigner"/> and optionally
/// releases the managed resources.
/// </summary>
/// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
protected override void Dispose ( bool disposing )
{
if ( disposing )
2017-11-27 13:11:20 -05:00
{
2023-03-31 11:47:53 -04:00
if ( BehaviorService ! = null & adorner ! = null )
2023-09-29 13:58:35 -04:00
BehaviorService ? . Adorners . Remove ( adorner ) ;
2023-03-31 11:47:53 -04:00
var ss = SelectionService ;
if ( ss ! = null )
ss . SelectionChanged - = OnSelectionChanged ;
var cs = ComponentChangeService ;
if ( cs ! = null )
cs . ComponentChanged - = OnComponentChanged ;
2017-11-27 13:11:20 -05:00
}
2023-03-31 11:47:53 -04:00
base . Dispose ( disposing ) ;
}
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the service.</summary>
/// <typeparam name="TS">The type of the s.</typeparam>
/// <returns></returns>
protected virtual TS GetService < TS > ( ) where TS : class = > ( TS ) GetService ( typeof ( TS ) ) ;
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Called when [component changed].</summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="ComponentChangedEventArgs"/> instance containing the event data.</param>
2023-09-29 13:58:35 -04:00
protected virtual void OnComponentChanged ( object? sender , ComponentChangedEventArgs e )
2023-03-31 11:47:53 -04:00
{
2017-11-27 13:11:20 -05:00
}
2023-03-31 11:47:53 -04:00
/// <summary>Called when [selection changed].</summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
2023-09-29 13:58:35 -04:00
protected virtual void OnSelectionChanged ( object? sender , EventArgs e )
2017-11-27 13:11:20 -05:00
{
2023-03-31 11:47:53 -04:00
}
}
2020-04-02 23:59:18 -04:00
2023-03-31 11:47:53 -04:00
/// <summary>A designer for controls that support attributes.</summary>
/// <typeparam name="TControl">The type of the control.</typeparam>
2023-09-29 13:58:35 -04:00
/// <seealso cref="ControlDesigner"/>
2023-03-31 11:47:53 -04:00
public abstract class AttributedControlDesigner < TControl > : ControlDesigner where TControl : Control
{
2023-09-29 13:58:35 -04:00
private readonly IDictionary < string , List < Attribute > > ? redirectedEvents ;
private readonly IDictionary < string , List < Attribute > > ? redirectedProps ;
private readonly DesignerVerbCollection ? verbs ;
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Initializes a new instance of the <see cref="AttributedControlDesigner{TControl}"/> class.</summary>
public AttributedControlDesigner ( )
{
redirectedEvents = this . GetRedirectedEvents ( ) ;
redirectedProps = this . GetRedirectedProperties ( ) ;
verbs = this . GetAttributedVerbs ( ) ;
}
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the design-time verbs supported by the component that is associated with the designer.</summary>
2023-09-29 13:58:35 -04:00
public override DesignerVerbCollection ? Verbs = > verbs ;
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the design-time action lists supported by the component associated with the designer.</summary>
public override DesignerActionListCollection ActionLists = >
this . GetActionLists ( Control , Actions , base . ActionLists , Verbs ) ;
2020-08-05 12:47:07 -04:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the control that the designer is designing.</summary>
public new TControl Control = > ( TControl ) base . Control ;
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the actions.</summary>
/// <value>The actions.</value>
2023-09-29 13:58:35 -04:00
protected virtual AttributedDesignerActionList ? Actions = > null ;
2020-08-05 12:47:07 -04:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the events to remove.</summary>
/// <value>The events to remove.</value>
2023-09-29 13:58:35 -04:00
protected virtual IEnumerable < string > ? EventsToRemove = > null ;
2020-08-05 12:47:07 -04:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the properties to remove.</summary>
/// <value>The properties to remove.</value>
2023-09-29 13:58:35 -04:00
protected virtual IEnumerable < string > ? PropertiesToRemove = > null ;
2020-08-05 12:47:07 -04:00
2023-03-31 11:47:53 -04:00
/// <summary>Allows a designer to add to the set of events that it exposes through a <see cref="T:System.ComponentModel.TypeDescriptor"/>.</summary>
/// <param name="events">The events for the class of the component.</param>
protected override void PreFilterEvents ( IDictionary events )
{
base . PreFilterEvents ( events ) ;
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
if ( redirectedEvents ! = null )
this . RedirectRegisteredEvents ( events , redirectedEvents ) ;
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
if ( EventsToRemove ! = null )
this . RemoveItems ( events , EventsToRemove ) ;
2017-11-27 13:11:20 -05:00
}
2023-03-31 11:47:53 -04:00
/// <summary>Adjusts the set of properties the component exposes through a <see cref="T:System.ComponentModel.TypeDescriptor"/>.</summary>
/// <param name="properties">An <see cref="T:System.Collections.IDictionary"/> containing the properties for the class of the component.</param>
protected override void PreFilterProperties ( IDictionary properties )
2017-11-27 13:11:20 -05:00
{
2023-03-31 11:47:53 -04:00
base . PreFilterProperties ( properties ) ;
2020-04-02 23:59:18 -04:00
2023-03-31 11:47:53 -04:00
if ( redirectedProps ! = null )
this . RedirectRegisteredProperties ( properties , redirectedProps ) ;
2020-04-02 23:59:18 -04:00
2023-03-31 11:47:53 -04:00
if ( PropertiesToRemove ! = null )
this . RemoveItems ( properties , PropertiesToRemove ) ;
}
}
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>An extended designer for controls that support attributes.</summary>
/// <typeparam name="TControl">The type of the control.</typeparam>
2023-09-29 13:58:35 -04:00
/// <seealso cref="AttributedControlDesigner{TControl}"/>
2023-03-31 11:47:53 -04:00
public abstract class AttributedControlDesignerEx < TControl > : AttributedControlDesigner < TControl > where TControl : Control
{
2023-09-29 13:58:35 -04:00
private Adorner ? adorner ;
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the component change service.</summary>
/// <value>The component change service.</value>
2023-09-29 13:58:35 -04:00
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
2023-03-31 11:47:53 -04:00
public IComponentChangeService ComponentChangeService { get ; private set ; }
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the selection service.</summary>
/// <value>The selection service.</value>
public ISelectionService SelectionService { get ; private set ; }
2023-09-29 13:58:35 -04:00
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the <see cref="T:System.Windows.Forms.Design.Behavior.BehaviorService"/> from the design environment.</summary>
public new BehaviorService BehaviorService = > base . BehaviorService ;
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the glyphs.</summary>
/// <value>The glyphs.</value>
public virtual GlyphCollection Glyphs = > Adorner . Glyphs ;
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
internal Adorner Adorner
{
get
2017-11-27 13:11:20 -05:00
{
2023-03-31 11:47:53 -04:00
if ( adorner = = null )
BehaviorService . Adorners . Add ( adorner = new Adorner ( ) ) ;
return adorner ;
2017-11-27 13:11:20 -05:00
}
2023-03-31 11:47:53 -04:00
}
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Initializes the designer with the specified component.</summary>
/// <param name="component">
/// The <see cref="T:System.ComponentModel.IComponent"/> to associate the designer with. This component must always be an instance
/// of, or derive from, <see cref="T:System.Windows.Forms.Control"/>.
/// </param>
public override void Initialize ( IComponent component )
{
base . Initialize ( component ) ;
SelectionService = GetService < ISelectionService > ( ) ;
2023-09-29 13:58:35 -04:00
SelectionService . SelectionChanged + = OnSelectionChanged ;
2023-03-31 11:47:53 -04:00
ComponentChangeService = GetService < IComponentChangeService > ( ) ;
2023-09-29 13:58:35 -04:00
ComponentChangeService . ComponentChanged + = OnComponentChanged ;
2023-03-31 11:47:53 -04:00
}
/// <summary>
/// Releases the unmanaged resources used by the <see cref="T:System.Windows.Forms.Design.ControlDesigner"/> and optionally releases
/// the managed resources.
/// </summary>
/// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
protected override void Dispose ( bool disposing )
{
if ( disposing )
2017-11-27 13:11:20 -05:00
{
2023-03-31 11:47:53 -04:00
BehaviorService ? . Adorners . Remove ( adorner ) ;
var ss = SelectionService ;
if ( ss ! = null )
ss . SelectionChanged - = OnSelectionChanged ;
var cs = ComponentChangeService ;
if ( cs ! = null )
cs . ComponentChanged - = OnComponentChanged ;
2017-11-27 13:11:20 -05:00
}
2023-03-31 11:47:53 -04:00
base . Dispose ( disposing ) ;
2017-11-27 13:11:20 -05:00
}
2023-03-31 11:47:53 -04:00
/// <summary>Gets the service.</summary>
/// <typeparam name="TS">The type of the s.</typeparam>
/// <returns></returns>
protected virtual TS GetService < TS > ( ) where TS : class = > ( TS ) GetService ( typeof ( TS ) ) ;
/// <summary>Called when a component has changed.</summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="ComponentChangedEventArgs"/> instance containing the event data.</param>
2023-09-29 13:58:35 -04:00
protected virtual void OnComponentChanged ( object? sender , ComponentChangedEventArgs e )
2017-11-27 13:11:20 -05:00
{
2023-03-31 11:47:53 -04:00
}
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Called when the selection on the designer has changed.</summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
2023-09-29 13:58:35 -04:00
protected virtual void OnSelectionChanged ( object? sender , EventArgs e )
2023-03-31 11:47:53 -04:00
{
}
}
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>A designer action list pulled from attributes.</summary>
2023-09-29 13:58:35 -04:00
/// <seealso cref="DesignerActionList"/>
2023-03-31 11:47:53 -04:00
public abstract class AttributedDesignerActionList : DesignerActionList
{
2023-09-29 13:58:35 -04:00
private IEnumerable < DesignerActionItem > ? fullAIList ;
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Initializes a new instance of the <see cref="AttributedDesignerActionList"/> class.</summary>
/// <param name="designer">The designer.</param>
/// <param name="component">The component.</param>
protected AttributedDesignerActionList ( ComponentDesigner designer , IComponent component )
: base ( component )
{
ParentDesigner = designer ;
AutoShow = true ;
}
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the parent designer.</summary>
/// <value>The parent designer.</value>
public ComponentDesigner ParentDesigner { get ; }
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>
/// Returns the collection of <see cref="T:System.ComponentModel.Design.DesignerActionItem"/> objects contained in the list.
/// </summary>
/// <returns>A <see cref="T:System.ComponentModel.Design.DesignerActionItem"/> array that contains the items in this list.</returns>
public override DesignerActionItemCollection GetSortedActionItems ( )
{
// Retrieve all attributed methods and properties
2023-09-29 13:58:35 -04:00
fullAIList ? ? = this . GetAllAttributedActionItems ( ) ;
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
// Filter for conditions and load
return this . GetFilteredActionItems ( fullAIList ) ;
}
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the component property.</summary>
/// <typeparam name="T"></typeparam>
/// <param name="propName">Name of the property.</param>
/// <returns></returns>
2023-09-29 13:58:35 -04:00
protected T ? GetComponentProperty < T > ( string propName )
2023-03-31 11:47:53 -04:00
{
var p = ComponentProp ( propName , typeof ( T ) ) ;
if ( p ! = null )
2023-09-29 13:58:35 -04:00
return ( T ? ) p . GetValue ( Component , null ) ;
2023-03-31 11:47:53 -04:00
return default ;
2017-11-27 13:11:20 -05:00
}
2023-03-31 11:47:53 -04:00
/// <summary>Sets the component property.</summary>
/// <typeparam name="T"></typeparam>
/// <param name="propName">Name of the property.</param>
/// <param name="value">The value.</param>
2023-09-29 13:58:35 -04:00
protected void SetComponentProperty < T > ( string propName , T value ) = > ComponentProp ( propName , typeof ( T ) ) ? . SetValue ( Component , value , null ) ;
2017-11-27 13:11:20 -05:00
2023-12-30 19:50:35 -05:00
private PropertyInfo ? ComponentProp ( string propName , Type retType ) = > Component ! . GetType ( ) . GetProperty ( propName , InternalComponentDesignerExtension . allInstBind , null , retType , Type . EmptyTypes , null ) ;
2023-03-31 11:47:53 -04:00
}
/// <summary>A designer for parent controls supported by attributes.</summary>
/// <typeparam name="TControl">The type of the control.</typeparam>
2023-09-29 13:58:35 -04:00
/// <seealso cref="ParentControlDesigner"/>
2023-03-31 11:47:53 -04:00
public abstract class AttributedParentControlDesigner < TControl > : ParentControlDesigner where TControl : Control
{
2023-09-29 13:58:35 -04:00
private readonly IDictionary < string , List < Attribute > > ? redirectedProps ;
private readonly DesignerVerbCollection ? verbs ;
2023-03-31 11:47:53 -04:00
/// <summary>Initializes a new instance of the <see cref="AttributedParentControlDesigner{TControl}"/> class.</summary>
public AttributedParentControlDesigner ( )
{
redirectedProps = this . GetRedirectedProperties ( ) ;
verbs = this . GetAttributedVerbs ( ) ;
}
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the design-time verbs supported by the component that is associated with the designer.</summary>
2023-09-29 13:58:35 -04:00
public override DesignerVerbCollection ? Verbs = > verbs ;
2020-04-02 23:59:18 -04:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the design-time action lists supported by the component associated with the designer.</summary>
public override DesignerActionListCollection ActionLists = >
this . GetActionLists ( Control , Actions , base . ActionLists , Verbs ) ;
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the control that the designer is designing.</summary>
public new TControl Control = > ( TControl ) base . Control ;
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the actions.</summary>
/// <value>The actions.</value>
2023-09-29 13:58:35 -04:00
protected virtual AttributedDesignerActionList ? Actions = > null ;
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the properties to remove.</summary>
/// <value>The properties to remove.</value>
2023-09-29 13:58:35 -04:00
protected virtual IEnumerable < string > ? PropertiesToRemove = > null ;
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Adjusts the set of properties the component will expose through a <see cref="T:System.ComponentModel.TypeDescriptor"/>.</summary>
/// <param name="properties">
/// An <see cref="T:System.Collections.IDictionary"/> that contains the properties for the class of the component.
/// </param>
protected override void PreFilterProperties ( IDictionary properties )
{
base . PreFilterProperties ( properties ) ;
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
if ( redirectedProps ! = null )
this . RedirectRegisteredProperties ( properties , redirectedProps ) ;
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
if ( PropertiesToRemove ! = null )
this . RemoveItems ( properties , PropertiesToRemove ) ;
2017-11-27 13:11:20 -05:00
}
2023-03-31 11:47:53 -04:00
}
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>An extended designer for parent controls supported by attributes.</summary>
/// <typeparam name="TControl">The type of the control.</typeparam>
2023-09-29 13:58:35 -04:00
/// <seealso cref="AttributedParentControlDesigner{TControl}"/>
2023-03-31 11:47:53 -04:00
public abstract class AttributedParentControlDesignerEx < TControl > : AttributedParentControlDesigner < TControl > where TControl : Control
{
2023-09-29 13:58:35 -04:00
private Adorner ? adorner ;
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the component change service.</summary>
/// <value>The component change service.</value>
2023-09-29 13:58:35 -04:00
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
2023-03-31 11:47:53 -04:00
public IComponentChangeService ComponentChangeService { get ; private set ; }
2020-04-02 23:59:18 -04:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the selection service.</summary>
/// <value>The selection service.</value>
public ISelectionService SelectionService { get ; private set ; }
2023-09-29 13:58:35 -04:00
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
2020-04-02 23:59:18 -04:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the <see cref="T:System.Windows.Forms.Design.Behavior.BehaviorService"/> from the design environment.</summary>
public new BehaviorService BehaviorService = > base . BehaviorService ;
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the glyphs.</summary>
/// <value>The glyphs.</value>
public virtual GlyphCollection Glyphs = > Adorner . Glyphs ;
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
internal Adorner Adorner
{
get
2017-11-27 13:11:20 -05:00
{
2023-03-31 11:47:53 -04:00
if ( adorner = = null )
BehaviorService . Adorners . Add ( adorner = new Adorner ( ) ) ;
return adorner ;
2017-11-27 13:11:20 -05:00
}
2023-03-31 11:47:53 -04:00
}
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Initializes the designer with the specified component.</summary>
/// <param name="component">The <see cref="T:System.ComponentModel.IComponent"/> to associate with the designer.</param>
public override void Initialize ( IComponent component )
{
base . Initialize ( component ) ;
SelectionService = GetService < ISelectionService > ( ) ;
2023-09-29 13:58:35 -04:00
SelectionService . SelectionChanged + = OnSelectionChanged ;
2023-03-31 11:47:53 -04:00
ComponentChangeService = GetService < IComponentChangeService > ( ) ;
2023-09-29 13:58:35 -04:00
ComponentChangeService . ComponentChanged + = OnComponentChanged ;
2023-03-31 11:47:53 -04:00
}
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>
/// Releases the unmanaged resources used by the <see cref="T:System.Windows.Forms.Design.ParentControlDesigner"/>, and optionally
/// releases the managed resources.
/// </summary>
/// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
protected override void Dispose ( bool disposing )
{
if ( disposing )
2017-11-27 13:11:20 -05:00
{
2023-09-29 13:58:35 -04:00
if ( adorner ! = null )
2023-03-31 11:47:53 -04:00
BehaviorService . Adorners . Remove ( adorner ) ;
var ss = SelectionService ;
if ( ss ! = null )
ss . SelectionChanged - = OnSelectionChanged ;
var cs = ComponentChangeService ;
if ( cs ! = null )
cs . ComponentChanged - = OnComponentChanged ;
2017-11-27 13:11:20 -05:00
}
2023-03-31 11:47:53 -04:00
base . Dispose ( disposing ) ;
}
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the service.</summary>
/// <typeparam name="TS">The type of the s.</typeparam>
/// <returns></returns>
protected virtual TS GetService < TS > ( ) where TS : class = > ( TS ) GetService ( typeof ( TS ) ) ;
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Called when [component changed].</summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="ComponentChangedEventArgs"/> instance containing the event data.</param>
2023-09-29 13:58:35 -04:00
protected virtual void OnComponentChanged ( object? sender , ComponentChangedEventArgs e )
2023-03-31 11:47:53 -04:00
{
}
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Called when [selection changed].</summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
2023-09-29 13:58:35 -04:00
protected virtual void OnSelectionChanged ( object? sender , EventArgs e )
2023-03-31 11:47:53 -04:00
{
2017-11-27 13:11:20 -05:00
}
2023-03-31 11:47:53 -04:00
}
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Attribute placed on methods that indicate they support a designer action.</summary>
2023-09-29 13:58:35 -04:00
/// <seealso cref="Attribute"/>
/// <seealso cref="IActionGetItem"/>
2023-03-31 11:47:53 -04:00
[AttributeUsage(AttributeTargets.Method)]
public sealed class DesignerActionMethodAttribute : Attribute , IActionGetItem
{
/// <summary>Initializes a new instance of the <see cref="DesignerActionMethodAttribute"/> class.</summary>
/// <param name="displayName">The display name.</param>
/// <param name="displayOrder">The display order.</param>
public DesignerActionMethodAttribute ( string displayName , int displayOrder = 0 )
2017-11-27 13:11:20 -05:00
{
2023-03-31 11:47:53 -04:00
DisplayName = displayName ;
DisplayOrder = displayOrder ;
}
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets or sets a value indicating whether [allow associate].</summary>
/// <value><see langword="true"/> if [allow associate]; otherwise, <see langword="false"/>.</value>
public bool AllowAssociate { get ; set ; }
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets or sets the category.</summary>
/// <value>The category.</value>
2023-09-29 13:58:35 -04:00
public string? Category { get ; set ; }
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets or sets the condition.</summary>
/// <value>The condition.</value>
2023-09-29 13:58:35 -04:00
public string? Condition { get ; set ; }
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets or sets the description.</summary>
/// <value>The description.</value>
2023-09-29 13:58:35 -04:00
public string? Description { get ; set ; }
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the display name.</summary>
/// <value>The display name.</value>
public string DisplayName { get ; }
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the display order.</summary>
/// <value>The display order.</value>
public int DisplayOrder { get ; }
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets or sets a value indicating whether [include as designer verb].</summary>
/// <value><see langword="true"/> if [include as designer verb]; otherwise, <see langword="false"/>.</value>
public bool IncludeAsDesignerVerb { get ; set ; }
2017-11-27 13:11:20 -05:00
2023-09-29 13:58:35 -04:00
DesignerActionItem IActionGetItem . GetItem ( DesignerActionList actions , MemberInfo mbr )
2023-03-31 11:47:53 -04:00
{
var ret = new DesignerActionMethodItem ( actions , mbr . Name , DisplayName , Category , Description , IncludeAsDesignerVerb )
{ AllowAssociate = AllowAssociate } ;
if ( ! string . IsNullOrEmpty ( Condition ) )
ret . Properties . Add ( "Condition" , Condition ) ;
ret . Properties . Add ( "Order" , DisplayOrder ) ;
return ret ;
2017-11-27 13:11:20 -05:00
}
2023-03-31 11:47:53 -04:00
}
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Attribute placed on properties that indicate they support a designer action.</summary>
2023-09-29 13:58:35 -04:00
/// <seealso cref="Attribute"/>
/// <seealso cref="IActionGetItem"/>
2023-03-31 11:47:53 -04:00
[AttributeUsage(AttributeTargets.Property)]
public sealed class DesignerActionPropertyAttribute : Attribute , IActionGetItem
{
/// <summary>Initializes a new instance of the <see cref="DesignerActionPropertyAttribute"/> class.</summary>
/// <param name="displayName">The display name.</param>
/// <param name="displayOrder">The display order.</param>
public DesignerActionPropertyAttribute ( string displayName , int displayOrder = 0 )
2017-11-27 13:11:20 -05:00
{
2023-03-31 11:47:53 -04:00
DisplayName = displayName ;
DisplayOrder = displayOrder ;
}
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets or sets a value indicating whether [allow associate].</summary>
/// <value><see langword="true"/> if [allow associate]; otherwise, <see langword="false"/>.</value>
public bool AllowAssociate { get ; set ; }
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets or sets the category.</summary>
/// <value>The category.</value>
2023-09-29 13:58:35 -04:00
public string? Category { get ; set ; }
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets or sets the condition.</summary>
/// <value>The condition.</value>
2023-09-29 13:58:35 -04:00
public string? Condition { get ; set ; }
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets or sets the description.</summary>
/// <value>The description.</value>
2023-09-29 13:58:35 -04:00
public string? Description { get ; set ; }
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the display name.</summary>
/// <value>The display name.</value>
public string DisplayName { get ; }
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the display order.</summary>
/// <value>The display order.</value>
public int DisplayOrder { get ; }
2017-11-27 13:11:20 -05:00
2023-09-29 13:58:35 -04:00
DesignerActionItem IActionGetItem . GetItem ( DesignerActionList actions , MemberInfo mbr )
2023-03-31 11:47:53 -04:00
{
var ret = new DesignerActionPropertyItem ( mbr . Name , DisplayName , Category , Description )
{ AllowAssociate = AllowAssociate } ;
if ( ! string . IsNullOrEmpty ( Condition ) )
ret . Properties . Add ( "Condition" , Condition ) ;
ret . Properties . Add ( "Order" , DisplayOrder ) ;
return ret ;
2017-11-27 13:11:20 -05:00
}
2023-03-31 11:47:53 -04:00
}
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Attribute placed on methods that indicate they support a designer attribute.</summary>
2023-09-29 13:58:35 -04:00
/// <seealso cref="Attribute"/>
2023-03-31 11:47:53 -04:00
[AttributeUsage(AttributeTargets.Method)]
public sealed class DesignerVerbAttribute : Attribute
{
2023-09-29 13:58:35 -04:00
private readonly CommandID ? cmdId ;
2023-03-31 11:47:53 -04:00
private readonly string menuText ;
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Initializes a new instance of the <see cref="DesignerVerbAttribute"/> class.</summary>
/// <param name="menuText">The menu text.</param>
2023-09-29 13:58:35 -04:00
public DesignerVerbAttribute ( string menuText ) = > this . menuText = menuText ;
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Initializes a new instance of the <see cref="DesignerVerbAttribute"/> class.</summary>
/// <param name="menuText">The menu text.</param>
/// <param name="commandMenuGroup">The command menu group.</param>
/// <param name="commandId">The command identifier.</param>
public DesignerVerbAttribute ( string menuText , Guid commandMenuGroup , int commandId )
{
this . menuText = menuText ;
cmdId = new CommandID ( commandMenuGroup , commandId ) ;
}
2017-11-27 13:11:20 -05:00
2023-09-29 13:58:35 -04:00
internal DesignerVerb GetDesignerVerb ( object obj , MethodInfo mi )
2023-03-31 11:47:53 -04:00
{
var handler = ( EventHandler ) Delegate . CreateDelegate ( typeof ( EventHandler ) , obj , mi ) ;
2023-09-29 13:58:35 -04:00
return cmdId ! = null ? new DesignerVerb ( menuText , handler , cmdId ) : new DesignerVerb ( menuText , handler ) ;
2017-11-27 13:11:20 -05:00
}
2023-03-31 11:47:53 -04:00
}
/// <summary>A service context implementation for an editor.</summary>
2023-09-29 13:58:35 -04:00
/// <seealso cref="IWindowsFormsEditorService"/>
/// <seealso cref="ITypeDescriptorContext"/>
2023-03-31 11:47:53 -04:00
public class EditorServiceContext : IWindowsFormsEditorService , ITypeDescriptorContext
{
private readonly ComponentDesigner designer ;
2023-09-29 13:58:35 -04:00
private readonly PropertyDescriptor ? targetProperty ;
private IComponentChangeService ? componentChangeSvc ;
2017-11-27 13:11:20 -05:00
2023-09-29 13:58:35 -04:00
internal EditorServiceContext ( ComponentDesigner designer ) = > this . designer = designer ;
2017-11-27 13:11:20 -05:00
2023-09-29 13:58:35 -04:00
internal EditorServiceContext ( ComponentDesigner designer , PropertyDescriptor ? prop )
2023-03-31 11:47:53 -04:00
{
this . designer = designer ;
targetProperty = prop ;
if ( prop = = null )
2017-11-27 13:11:20 -05:00
{
2023-03-31 11:47:53 -04:00
prop = TypeDescriptor . GetDefaultProperty ( designer . Component ) ;
2023-09-29 13:58:35 -04:00
if ( prop ! = null & & typeof ( ICollection ) . IsAssignableFrom ( prop . PropertyType ) )
2023-03-31 11:47:53 -04:00
targetProperty = prop ;
2017-11-27 13:11:20 -05:00
}
2023-03-31 11:47:53 -04:00
}
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
internal EditorServiceContext ( ComponentDesigner designer , PropertyDescriptor prop , string newVerbText )
2023-09-29 13:58:35 -04:00
: this ( designer , prop ) = > this . designer . Verbs . Add ( new DesignerVerb ( newVerbText , OnEditItems ) ) ;
2017-11-27 13:11:20 -05:00
2023-09-29 13:58:35 -04:00
IContainer ITypeDescriptorContext . Container = > designer . Component . Site ? . Container ? ? throw new InvalidOperationException ( ) ;
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
object ITypeDescriptorContext . Instance = > designer . Component ;
2017-11-27 13:11:20 -05:00
2023-09-29 13:58:35 -04:00
PropertyDescriptor ITypeDescriptorContext . PropertyDescriptor = > targetProperty ? ? throw new InvalidOperationException ( ) ;
2017-11-27 13:11:20 -05:00
2023-09-29 13:58:35 -04:00
private IComponentChangeService ChangeService = > componentChangeSvc ? ? = GetService < IComponentChangeService > ( ) ? ? throw new InvalidOperationException ( ) ;
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Shows the specified <see cref="T:System.Windows.Forms.Form"/>.</summary>
/// <param name="dialog">The <see cref="T:System.Windows.Forms.Form"/> to display.</param>
/// <returns>A <see cref="T:System.Windows.Forms.DialogResult"/> indicating the result code returned by the <see cref="T:System.Windows.Forms.Form"/>.</returns>
public DialogResult ShowDialog ( Form dialog )
{
var service = GetService < IUIService > ( ) ;
if ( service ! = null )
return service . ShowDialog ( dialog ) ;
return dialog . ShowDialog ( designer . Component as IWin32Window ) ;
}
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
void IWindowsFormsEditorService . CloseDropDown ( )
{
}
2017-11-27 13:11:20 -05:00
2023-12-30 19:50:35 -05:00
void IWindowsFormsEditorService . DropDownControl ( Control ? control )
2023-03-31 11:47:53 -04:00
{
}
2017-11-27 13:11:20 -05:00
2023-09-29 13:58:35 -04:00
object? IServiceProvider . GetService ( Type serviceType )
2023-03-31 11:47:53 -04:00
{
2023-09-29 13:58:35 -04:00
if ( serviceType = = typeof ( ITypeDescriptorContext ) | | serviceType = = typeof ( IWindowsFormsEditorService ) )
2023-03-31 11:47:53 -04:00
return this ;
return designer . Component ? . Site ? . GetService ( serviceType ) ;
}
2017-11-27 13:11:20 -05:00
2023-09-29 13:58:35 -04:00
void ITypeDescriptorContext . OnComponentChanged ( ) = > ChangeService . OnComponentChanged ( designer . Component , targetProperty , null , null ) ;
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
bool ITypeDescriptorContext . OnComponentChanging ( )
{
try
2017-11-27 13:11:20 -05:00
{
2023-03-31 11:47:53 -04:00
ChangeService . OnComponentChanging ( designer . Component , targetProperty ) ;
2017-11-27 13:11:20 -05:00
}
2023-03-31 11:47:53 -04:00
catch ( CheckoutException exception )
2017-11-27 13:11:20 -05:00
{
2023-03-31 11:47:53 -04:00
if ( exception ! = CheckoutException . Canceled )
throw ;
return false ;
2017-11-27 13:11:20 -05:00
}
2023-03-31 11:47:53 -04:00
return true ;
}
2017-11-27 13:11:20 -05:00
2023-09-29 13:58:35 -04:00
private T ? GetService < T > ( ) where T : class = > ( ( IServiceProvider ) this ) . GetService < T > ( ) ;
2017-11-27 13:11:20 -05:00
2023-09-29 13:58:35 -04:00
private void OnEditItems ( object? sender , EventArgs e )
2023-03-31 11:47:53 -04:00
{
2023-09-29 13:58:35 -04:00
var component = targetProperty ? . GetValue ( designer . Component ) ;
2023-03-31 11:47:53 -04:00
if ( component ! = null )
2017-11-27 13:11:20 -05:00
{
2023-03-31 11:47:53 -04:00
var editor = TypeDescriptor . GetEditor ( component , typeof ( UITypeEditor ) ) as CollectionEditor ;
editor ? . EditValue ( this , this , component ) ;
2017-11-27 13:11:20 -05:00
}
}
2023-03-31 11:47:53 -04:00
}
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Attribute placed on class items that indicate they support a designer redirected item.</summary>
2023-09-29 13:58:35 -04:00
/// <seealso cref="Attribute"/>
2023-03-31 11:47:53 -04:00
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Event | AttributeTargets.Method)]
public sealed class RedirectedDesignerItemAttribute : Attribute
{
/// <summary>Initializes a new instance of the <see cref="RedirectedDesignerItemAttribute"/> class.</summary>
2023-09-29 13:58:35 -04:00
public RedirectedDesignerItemAttribute ( ) = > ApplyOtherAttributes = true ;
2023-03-31 11:47:53 -04:00
/// <summary>Gets or sets a value indicating whether to apply other attributes.</summary>
/// <value><see langword="true"/> if this should apply other attributes; otherwise, <see langword="false"/>.</value>
public bool ApplyOtherAttributes { get ; set ; }
}
/// <summary>A behavior derivative for a supplied type.</summary>
/// <typeparam name="TControlDesigner">The type of the control designer.</typeparam>
2023-09-29 13:58:35 -04:00
/// <seealso cref="Behavior"/>
2023-03-31 11:47:53 -04:00
public abstract class TypedBehavior < TControlDesigner > : Behavior where TControlDesigner : ControlDesigner
{
/// <summary>Initializes a new instance of the <see cref="TypedBehavior{TControlDesigner}"/> class.</summary>
/// <param name="designer">The designer.</param>
2023-09-29 13:58:35 -04:00
protected TypedBehavior ( TControlDesigner designer ) = > Designer = designer ;
2020-04-02 23:59:18 -04:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the designer.</summary>
/// <value>The designer.</value>
public TControlDesigner Designer { get ; }
}
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>An action list for a generic designer.</summary>
/// <typeparam name="TComponentDesigner">The type of the component designer.</typeparam>
/// <typeparam name="TComponent">The type of the component.</typeparam>
2023-09-29 13:58:35 -04:00
/// <seealso cref="AttributedDesignerActionList"/>
2023-03-31 11:47:53 -04:00
public abstract class TypedDesignerActionList < TComponentDesigner , TComponent > : AttributedDesignerActionList where TComponentDesigner : ComponentDesigner where TComponent : Component
{
/// <summary>Initializes a new instance of the <see cref="TypedDesignerActionList{TComponentDesigner, TComponent}"/> class.</summary>
/// <param name="designer">The designer.</param>
/// <param name="component">The component.</param>
2023-09-29 13:58:35 -04:00
protected TypedDesignerActionList ( TComponentDesigner designer , TComponent component ) : base ( designer , component ) = > ParentDesigner = designer ;
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the parent designer.</summary>
/// <value>The parent designer.</value>
public new TComponentDesigner ParentDesigner { get ; }
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the component related to <see cref="T:System.ComponentModel.Design.DesignerActionList"/>.</summary>
2023-12-30 19:50:35 -05:00
public new TComponent Component = > ( TComponent ) base . Component ! ;
2023-03-31 11:47:53 -04:00
}
2020-04-02 23:59:18 -04:00
2023-03-31 11:47:53 -04:00
/// <summary>A glyph associated with a designer.</summary>
/// <typeparam name="TControlDesigner">The type of the control designer.</typeparam>
2023-09-29 13:58:35 -04:00
/// <seealso cref="Glyph"/>
/// <seealso cref="IDisposable"/>
2023-03-31 11:47:53 -04:00
public abstract class TypedGlyph < TControlDesigner > : Glyph , IDisposable where TControlDesigner : ControlDesigner
{
/// <summary>Initializes a new instance of the <see cref="TypedGlyph{TControlDesigner}"/> class.</summary>
/// <param name="designer">The designer.</param>
/// <param name="behavior">The behavior.</param>
2023-09-29 13:58:35 -04:00
protected TypedGlyph ( TControlDesigner designer , Behavior behavior ) : base ( behavior ) = > Designer = designer ;
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the designer.</summary>
/// <value>The designer.</value>
public TControlDesigner Designer { get ; }
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
public virtual void Dispose ( ) { }
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Sets the behavior.</summary>
/// <param name="b">The b.</param>
2023-09-29 13:58:35 -04:00
public void SetBehavior ( TypedBehavior < TControlDesigner > b ) = > base . SetBehavior ( b ) ;
2023-03-31 11:47:53 -04:00
}
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
internal static class InternalComponentDesignerExtension
{
public const BindingFlags allInstBind = BindingFlags . NonPublic | BindingFlags . Public | BindingFlags . Instance ;
2017-11-27 13:11:20 -05:00
2023-09-29 13:58:35 -04:00
public static DesignerActionListCollection GetActionLists ( this ComponentDesigner designer , Component component , AttributedDesignerActionList ? actions , DesignerActionListCollection ? baseActions , DesignerVerbCollection ? verbs )
2017-11-27 13:11:20 -05:00
{
2023-03-31 11:47:53 -04:00
var lists = new DesignerActionListCollection ( ) ;
if ( baseActions ! = null & & baseActions . Count > 0 )
lists . AddRange ( baseActions ) ;
if ( actions ! = null )
lists . Add ( actions ) ;
if ( verbs ! = null & & verbs . Count > 0 )
lists . Add ( new DesignerActionVerbList ( verbs ) ) ;
return lists ;
}
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
public static IEnumerable < DesignerActionItem > GetAllAttributedActionItems ( this DesignerActionList actionList )
{
var fullAIList = new List < DesignerActionItem > ( ) ;
foreach ( var mbr in actionList . GetType ( ) . GetMethods ( allInstBind ) )
2017-11-27 13:11:20 -05:00
{
2023-03-31 11:47:53 -04:00
foreach ( IActionGetItem attr in mbr . GetCustomAttributes ( typeof ( DesignerActionMethodAttribute ) , true ) )
2017-11-27 13:11:20 -05:00
{
2023-03-31 11:47:53 -04:00
if ( mbr . ReturnType = = typeof ( void ) & & mbr . GetParameters ( ) . Length = = 0 )
2017-11-27 13:11:20 -05:00
fullAIList . Add ( attr . GetItem ( actionList , mbr ) ) ;
2023-03-31 11:47:53 -04:00
else
throw new FormatException ( "DesignerActionMethodAttribute must be applied to a method returning void and having no parameters." ) ;
2017-11-27 13:11:20 -05:00
}
2023-03-31 11:47:53 -04:00
}
foreach ( var mbr in actionList . GetType ( ) . GetProperties ( allInstBind ) )
{
if ( mbr . GetIndexParameters ( ) . Length > 0 )
throw new FormatException ( "DesignerActionPropertyAttribute must be applied to non-indexed properties." ) ;
foreach ( IActionGetItem attr in mbr . GetCustomAttributes ( typeof ( DesignerActionPropertyAttribute ) , true ) )
fullAIList . Add ( attr . GetItem ( actionList , mbr ) ) ;
}
fullAIList . Sort ( CompareItems ) ;
return fullAIList ;
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
int CompareItems ( DesignerActionItem a , DesignerActionItem b )
{
var c = string . Compare ( a ? . Category ? ? string . Empty , b ? . Category ? ? string . Empty , true ) ;
if ( c ! = 0 )
return c ;
c = ( int ) ( a ? . Properties [ "Order" ] ? ? 0 ) - ( int ) ( b ? . Properties [ "Order" ] ? ? 0 ) ;
if ( c ! = 0 )
return c ;
return string . Compare ( a ? . DisplayName , b ? . DisplayName , true ) ;
2017-11-27 13:11:20 -05:00
}
2023-03-31 11:47:53 -04:00
}
2017-11-27 13:11:20 -05:00
2023-09-29 13:58:35 -04:00
public static DesignerVerbCollection ? GetAttributedVerbs ( this ComponentDesigner designer )
2023-03-31 11:47:53 -04:00
{
var verbs = new DesignerVerbCollection ( ) ;
foreach ( var m in designer . GetType ( ) . GetMethods ( allInstBind ) )
2017-11-27 13:11:20 -05:00
{
2023-03-31 11:47:53 -04:00
foreach ( DesignerVerbAttribute attr in m . GetCustomAttributes ( typeof ( DesignerVerbAttribute ) , true ) )
2017-11-27 13:11:20 -05:00
{
2023-03-31 11:47:53 -04:00
verbs . Add ( attr . GetDesignerVerb ( designer , m ) ) ;
2017-11-27 13:11:20 -05:00
}
}
2023-03-31 11:47:53 -04:00
return verbs . Count > 0 ? verbs : null ;
}
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
public static DesignerActionItemCollection GetFilteredActionItems ( this DesignerActionList actionList , IEnumerable < DesignerActionItem > fullAIList )
{
var col = new DesignerActionItemCollection ( ) ;
foreach ( var ai in fullAIList )
if ( CheckCondition ( ai ) )
col . Add ( ai ) ;
// Add header items for displayed items
2023-09-29 13:58:35 -04:00
string? cat = null ;
2023-03-31 11:47:53 -04:00
for ( var i = 0 ; i < col . Count ; i + + )
2017-11-27 13:11:20 -05:00
{
2023-03-31 11:47:53 -04:00
var curCat = col [ i ] . Category ;
if ( string . Compare ( curCat , cat , true ) ! = 0 )
2017-11-27 13:11:20 -05:00
{
2023-12-30 19:50:35 -05:00
col . Insert ( i + + , new DesignerActionHeaderItem ( curCat ! ) ) ;
2023-03-31 11:47:53 -04:00
cat = curCat ;
2017-11-27 13:11:20 -05:00
}
2023-03-31 11:47:53 -04:00
}
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
return col ;
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
bool CheckCondition ( DesignerActionItem ai )
{
if ( ai . Properties [ "Condition" ] ! = null )
2017-11-27 13:11:20 -05:00
{
2023-09-29 13:58:35 -04:00
var p = actionList . GetType ( ) . GetProperty ( ( string ) ai . Properties [ "Condition" ] ! , allInstBind , null , typeof ( bool ) , Type . EmptyTypes , null ) ;
2023-03-31 11:47:53 -04:00
if ( p ! = null )
2023-09-29 13:58:35 -04:00
return ( bool ) p . GetValue ( actionList , null ) ! ;
2017-11-27 13:11:20 -05:00
}
2023-03-31 11:47:53 -04:00
return true ;
2017-11-27 13:11:20 -05:00
}
2023-03-31 11:47:53 -04:00
}
2017-11-27 13:11:20 -05:00
2023-09-29 13:58:35 -04:00
public static IDictionary < string , List < Attribute > > ? GetRedirectedEvents ( this ComponentDesigner d )
2023-03-31 11:47:53 -04:00
{
var ret = new Dictionary < string , List < Attribute > > ( ) ;
foreach ( var evt in d . GetType ( ) . GetEvents ( allInstBind ) )
2020-08-05 12:47:07 -04:00
{
2023-03-31 11:47:53 -04:00
foreach ( var attr in evt . GetCustomAttributes < RedirectedDesignerItemAttribute > ( false ) )
2020-08-05 12:47:07 -04:00
{
2023-03-31 11:47:53 -04:00
var attributes = attr . ApplyOtherAttributes
2023-09-29 13:58:35 -04:00
? evt . GetCustomAttributes < Attribute > ( ) . Where ( a = > a is not RedirectedDesignerItemAttribute ) . ToList ( )
2023-03-31 11:47:53 -04:00
: new List < Attribute > ( ) ;
ret . Add ( evt . Name , attributes ) ;
2020-08-05 12:47:07 -04:00
}
}
2023-03-31 11:47:53 -04:00
return ret . Count > 0 ? ret : null ;
}
2020-08-05 12:47:07 -04:00
2023-03-31 11:47:53 -04:00
public static void RedirectRegisteredEvents ( this ComponentDesigner d , IDictionary properties , IDictionary < string , List < Attribute > > redirectedProps )
{
foreach ( var propName in redirectedProps . Keys )
2020-08-05 12:47:07 -04:00
{
2023-09-29 13:58:35 -04:00
var oldPropertyDescriptor = ( PropertyDescriptor ? ) properties [ propName ] ;
2023-03-31 11:47:53 -04:00
if ( oldPropertyDescriptor ! = null )
2020-08-05 12:47:07 -04:00
{
2023-03-31 11:47:53 -04:00
var attributes = redirectedProps [ propName ] ;
properties [ propName ] = TypeDescriptor . CreateProperty ( d . GetType ( ) , oldPropertyDescriptor , attributes . ToArray ( ) ) ;
2020-08-05 12:47:07 -04:00
}
}
2023-03-31 11:47:53 -04:00
}
2020-08-05 12:47:07 -04:00
2023-09-29 13:58:35 -04:00
public static IDictionary < string , List < Attribute > > ? GetRedirectedProperties ( this ComponentDesigner d )
2023-03-31 11:47:53 -04:00
{
var ret = new Dictionary < string , List < Attribute > > ( ) ;
foreach ( var prop in d . GetType ( ) . GetProperties ( allInstBind ) )
2017-11-27 13:11:20 -05:00
{
2023-03-31 11:47:53 -04:00
foreach ( var attr in prop . GetCustomAttributes < RedirectedDesignerItemAttribute > ( false ) )
2017-11-27 13:11:20 -05:00
{
2023-03-31 11:47:53 -04:00
var attributes = attr . ApplyOtherAttributes
2023-09-29 13:58:35 -04:00
? prop . GetCustomAttributes < Attribute > ( ) . Where ( a = > a is not RedirectedDesignerItemAttribute ) . ToList ( )
2023-03-31 11:47:53 -04:00
: new List < Attribute > ( ) ;
ret . Add ( prop . Name , attributes ) ;
2017-11-27 13:11:20 -05:00
}
}
2023-03-31 11:47:53 -04:00
return ret . Count > 0 ? ret : null ;
}
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
public static void RedirectRegisteredProperties ( this ComponentDesigner d , IDictionary properties , IDictionary < string , List < Attribute > > redirectedProps )
{
foreach ( var propName in redirectedProps . Keys )
2017-11-27 13:11:20 -05:00
{
2023-09-29 13:58:35 -04:00
var oldPropertyDescriptor = ( PropertyDescriptor ? ) properties [ propName ] ;
2023-03-31 11:47:53 -04:00
if ( oldPropertyDescriptor ! = null )
2017-11-27 13:11:20 -05:00
{
2023-03-31 11:47:53 -04:00
var attributes = redirectedProps [ propName ] ;
properties [ propName ] = TypeDescriptor . CreateProperty ( d . GetType ( ) , oldPropertyDescriptor , attributes . ToArray ( ) ) ;
2017-11-27 13:11:20 -05:00
}
}
2023-03-31 11:47:53 -04:00
}
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
public static void RemoveItems ( this ComponentDesigner d , IDictionary values , IEnumerable < string > keysToRemove )
{
foreach ( var p in keysToRemove )
if ( values . Contains ( p ) )
values . Remove ( p ) ;
2017-11-27 13:11:20 -05:00
}
2023-03-31 11:47:53 -04:00
}
internal class DesignerActionVerbList : DesignerActionList
{
private DesignerVerbCollection _verbs ;
2017-11-27 13:11:20 -05:00
2023-09-29 13:58:35 -04:00
public DesignerActionVerbList ( DesignerVerbCollection verbs ) : base ( null ) = > _verbs = verbs ;
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
public override bool AutoShow = > false ;
public override DesignerActionItemCollection GetSortedActionItems ( )
{
2023-09-24 17:26:46 -04:00
DesignerActionItemCollection items = new ( ) ;
2023-09-29 13:58:35 -04:00
foreach ( DesignerVerb v in _verbs . Cast < DesignerVerb > ( ) )
if ( v . Visible & & v . Enabled & & v . Supported )
2023-03-31 11:47:53 -04:00
items . Add ( new DesignerActionVerbItem ( v ) ) ;
return items ;
}
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
public class DesignerActionVerbItem : DesignerActionMethodItem
{
private DesignerVerb targetVerb ;
2017-11-27 13:11:20 -05:00
2023-09-29 13:58:35 -04:00
public DesignerActionVerbItem ( DesignerVerb verb ) : base ( null , null , verb . Text , "Verbs" , verb . Description , false ) = > targetVerb = verb ;
2017-11-27 13:11:20 -05:00
2023-09-29 13:58:35 -04:00
public override void Invoke ( ) = > targetVerb . Invoke ( ) ;
2017-11-27 13:11:20 -05:00
}
}