diff --git a/src/System.Windows.Forms/src/misc/ClientUtils.cs b/src/Common/src/ClientUtils.cs similarity index 100% rename from src/System.Windows.Forms/src/misc/ClientUtils.cs rename to src/Common/src/ClientUtils.cs index 69e486e2a7f..246116a1c8f 100644 --- a/src/System.Windows.Forms/src/misc/ClientUtils.cs +++ b/src/Common/src/ClientUtils.cs @@ -16,11 +16,11 @@ namespace System.Windows.Forms #endif { using System; - using System.Reflection; - using System.Diagnostics.CodeAnalysis; - using System.Globalization; using System.Collections; using System.Diagnostics; + using System.Diagnostics.CodeAnalysis; + using System.Globalization; + using System.Reflection; // Miscellaneous utilities static internal class ClientUtils { diff --git a/src/System.Windows.Forms/src/misc/DpiHelper.DpiAwarenessContext.cs b/src/Common/src/DpiHelper.DpiAwarenessContext.cs similarity index 100% rename from src/System.Windows.Forms/src/misc/DpiHelper.DpiAwarenessContext.cs rename to src/Common/src/DpiHelper.DpiAwarenessContext.cs diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/RTLAwareMessageBox.cs b/src/Common/src/RTLAwareMessageBox.cs similarity index 64% rename from src/System.Windows.Forms/src/System/Windows/Forms/RTLAwareMessageBox.cs rename to src/Common/src/RTLAwareMessageBox.cs index 591d464dc4d..0fc63a706cd 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/RTLAwareMessageBox.cs +++ b/src/Common/src/RTLAwareMessageBox.cs @@ -4,26 +4,19 @@ namespace System.Windows.Forms { - using System; - using System.Windows.Forms; - - /// - /// - /// - /// The Show method displays a message box that can contain text, buttons, and symbols that - /// inform and instruct the user. This MessageBox will be RTL, if the resources - /// for this dll have been localized to a RTL language. - /// - /// + + using System.Resources; + + /// + /// The Show method displays a message box that can contain text, buttons, and symbols that inform and instruct the user. + /// This MessageBox will be RTL, if the resources for this dll have been localized to a RTL language. + /// internal sealed class RTLAwareMessageBox { - /// - /// - /// + /// /// Displays a message box with specified text, caption, and style. /// Makes the dialog RTL if the resources for this dll have been localized to a RTL language. - /// - /// + /// public static DialogResult Show(IWin32Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, MessageBoxOptions options) { if (RTLAwareMessageBox.IsRTLResources) { @@ -32,10 +25,9 @@ public static DialogResult Show(IWin32Window owner, string text, string caption, return MessageBox.Show(owner, text, caption, buttons, icon, defaultButton, options); } - /// - /// Tells whether the current resources for this dll have been - /// localized for a RTL language. - /// + /// + /// Tells whether the current resources for this dll have been localized for a RTL language. + /// public static bool IsRTLResources { get { return SR.RTL != "RTL_False"; diff --git a/src/System.Design/src/ApiCompatBaseline.netcoreapp.txt b/src/System.Design/src/ApiCompatBaseline.netcoreapp.txt index 9aeed202edd..b2062a38035 100644 --- a/src/System.Design/src/ApiCompatBaseline.netcoreapp.txt +++ b/src/System.Design/src/ApiCompatBaseline.netcoreapp.txt @@ -4,7 +4,6 @@ TypesMustExist : Type 'System.ComponentModel.Design.ActiveDesignSurfaceChangedEv TypesMustExist : Type 'System.ComponentModel.Design.ArrayEditor' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'System.ComponentModel.Design.BinaryEditor' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'System.ComponentModel.Design.ByteViewer' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ComponentModel.Design.CollectionEditor' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'System.ComponentModel.Design.ComponentActionsType' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'System.ComponentModel.Design.DateTimeEditor' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'System.ComponentModel.Design.DesignerActionHeaderItem' does not exist in the implementation but it does exist in the contract. @@ -41,7 +40,6 @@ TypesMustExist : Type 'System.ComponentModel.Design.MenuCommandsChangedEventHand TypesMustExist : Type 'System.ComponentModel.Design.MenuCommandsChangedType' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'System.ComponentModel.Design.MenuCommandService' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'System.ComponentModel.Design.MultilineStringEditor' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ComponentModel.Design.ObjectSelectorEditor' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'System.ComponentModel.Design.ProjectTargetFrameworkAttribute' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'System.ComponentModel.Design.UndoEngine' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'System.ComponentModel.Design.Data.DataSourceDescriptor' does not exist in the implementation but it does exist in the contract. diff --git a/src/System.Windows.Forms.Design.Editors/ref/System.Windows.Forms.Design.Editors.Ref.csproj b/src/System.Windows.Forms.Design.Editors/ref/System.Windows.Forms.Design.Editors.Ref.csproj index e23b857822f..65b9a26d734 100644 --- a/src/System.Windows.Forms.Design.Editors/ref/System.Windows.Forms.Design.Editors.Ref.csproj +++ b/src/System.Windows.Forms.Design.Editors/ref/System.Windows.Forms.Design.Editors.Ref.csproj @@ -3,6 +3,7 @@ netcoreapp3.0 System.Windows.Forms.Design.Editors + System.ComponentModel.Design false diff --git a/src/System.Windows.Forms.Design.Editors/ref/System.Windows.Forms.Design.Editors.cs b/src/System.Windows.Forms.Design.Editors/ref/System.Windows.Forms.Design.Editors.cs index 37c733f48f8..02b328533a5 100644 --- a/src/System.Windows.Forms.Design.Editors/ref/System.Windows.Forms.Design.Editors.cs +++ b/src/System.Windows.Forms.Design.Editors/ref/System.Windows.Forms.Design.Editors.cs @@ -6,6 +6,10 @@ // Changes to this file must follow the http://aka.ms/api-review process. // ------------------------------------------------------------------------------ +using System.Collections; +using System.ComponentModel; +using System.Drawing.Design; + namespace System.Drawing.Design { [System.CLSCompliantAttribute(false)] @@ -147,3 +151,81 @@ public ShortcutKeysEditor() { } public override System.Drawing.Design.UITypeEditorEditStyle GetEditStyle(System.ComponentModel.ITypeDescriptorContext context) { throw null; } } } +namespace System.ComponentModel.Design +{ + [System.CLSCompliantAttribute(false)] + public partial class CollectionEditor : System.Drawing.Design.UITypeEditor + { + public CollectionEditor() { } + public CollectionEditor(Type type) { } + protected Type CollectionItemType { get { throw null; } } + protected Type CollectionType { get { throw null; } } + protected ITypeDescriptorContext Context { get { throw null; } } + protected Type[] NewItemTypes { get { throw null; } } + protected virtual string HelpTopic { get { throw null; } } + protected virtual bool CanRemoveInstance(object value) { throw null; } + protected virtual bool CanSelectMultipleInstances() { throw null; } + protected virtual CollectionForm CreateCollectionForm() { throw null; } + protected virtual object CreateInstance(Type itemType) { throw null; } + protected virtual IList GetObjectsFromInstance(object instance) { throw null; } + protected virtual string GetDisplayText(object value) { throw null; } + protected virtual Type CreateCollectionItemType() { throw null; } + protected virtual Type[] CreateNewItemTypes() { throw null; } + protected virtual void DestroyInstance(object instance) { throw null; } + public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) { throw null; } + public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) { throw null; } + protected virtual object[] GetItems(object editValue) { throw null; } + protected object GetService(Type serviceType) { throw null; } + protected virtual object SetItems(object editValue, object[] value) { throw null; } + protected virtual void ShowHelp() { } + protected abstract class CollectionForm : System.Windows.Forms.Form + { + public CollectionForm(CollectionEditor editor) { } + protected Type CollectionItemType { get { throw null; } } + protected Type CollectionType { get { throw null; } } + protected ITypeDescriptorContext Context { get { throw null; } } + public object EditValue { get { throw null; } set { } } + protected object[] Items { get { throw null; } set { } } + protected Type[] NewItemTypes { get { throw null; } } + protected bool CanRemoveInstance(object value) { throw null; } + protected virtual bool CanSelectMultipleInstances() { throw null; } + protected object CreateInstance(Type itemType) { throw null; } + protected void DestroyInstance(object instance) { } + protected virtual void DisplayError(Exception e) { } + protected override object GetService(Type serviceType) { throw null; } + protected internal virtual System.Windows.Forms.DialogResult ShowEditorDialog(System.Windows.Forms.Design.IWindowsFormsEditorService edSvc) { throw null; } + protected abstract void OnEditValueChanged(); + } + } + + [System.CLSCompliantAttribute(false)] + public partial class ObjectSelectorEditor : System.Drawing.Design.UITypeEditor + { + public ObjectSelectorEditor() { } + public ObjectSelectorEditor(bool subObjectSelector) { } + public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) { throw null; } + public static void ApplyTreeViewThemeStyles(System.Windows.Forms.TreeView treeView) { } + public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) { throw null; } + public bool EqualsToValue(object value) { throw null; } + protected virtual void FillTreeWithData(Selector selector, ITypeDescriptorContext context, IServiceProvider provider) { } + public virtual void SetValue(object value) { } + public class Selector : System.Windows.Forms.TreeView + { + public Selector(ObjectSelectorEditor editor) { } + public SelectorNode AddNode(string label, object value, SelectorNode parent) { throw null; } + public void Clear() { } + protected void OnAfterSelect(object sender, System.Windows.Forms.TreeViewEventArgs e) { } + protected override void OnKeyDown(System.Windows.Forms.KeyEventArgs e) { } + protected override void OnKeyPress(System.Windows.Forms.KeyPressEventArgs e) { } + protected override void OnNodeMouseClick(System.Windows.Forms.TreeNodeMouseClickEventArgs e) { } + public bool SetSelection(object value, System.Windows.Forms.TreeNodeCollection nodes) { throw null; } + public void Start(System.Windows.Forms.Design.IWindowsFormsEditorService edSvc, object value) { } + public void Stop() { } + protected override void WndProc(ref System.Windows.Forms.Message m) { } + } + public class SelectorNode : System.Windows.Forms.TreeNode + { + public SelectorNode(string label, object value) : base(label) { } + } + } +} diff --git a/src/System.Windows.Forms.Design.Editors/src/Resources/CollectionEditor.resx b/src/System.Windows.Forms.Design.Editors/src/Resources/CollectionEditor.resx new file mode 100644 index 00000000000..98d98548cae --- /dev/null +++ b/src/System.Windows.Forms.Design.Editors/src/Resources/CollectionEditor.resx @@ -0,0 +1,556 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + Left + + + + True + + + NoControl + + + + 3, 0 + + + No + + + 53, 13 + + + 0 + + + &Members: + + + membersLabel + + + System.Windows.Forms.Label, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + overArchingTableLayoutPanel + + + 3 + + + Top, Bottom, Left, Right + + + True + + + NoControl + + + False + + + 3, 17 + + + No + + + Top, Bottom, Left, Right + + + 3 + + + Move Down + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAElJREFUOE9jYBje + 4MCBA/9hmGSfgjQCNcExlE+8OUPUAHRnI4cB0eFByBCiAhOXIURphsUTxbEAMghmCEk2o6cUijQTn+wo + UAkAY/VsRlvaylwAAAAASUVORK5CYII= + + + + NoControl + + + 198, 47 + + + 3, 1, 18, 3 + + + No + + + 24, 24 + + + 4 + + + downButton + + + System.Windows.Forms.Button, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + overArchingTableLayoutPanel + + + 0 + + + Left, Right + + + True + + + 3 + + + Top, Bottom, Left, Right + + + True + + + NoControl + + + 3, 3 + + + No + + + 78, 23 + + + 0 + + + &Add + + + addButton + + + System.Windows.Forms.Button, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + addRemoveTableLayoutPanel + + + 0 + + + Top, Bottom, Left, Right + + + True + + + NoControl + + + 108, 3 + + + No + + + 78, 23 + + + 2 + + + &Remove + + + removeButton + + + System.Windows.Forms.Button, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + addRemoveTableLayoutPanel + + + 1 + + + 3, 243 + + + 1 + + + 189, 29 + + + 2 + + + addRemoveTableLayoutPanel + + + System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + overArchingTableLayoutPanel + + + 1 + + + <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="addButton" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="removeButton" Row="0" RowSpan="1" Column="2" ColumnSpan="1" /></Controls><Columns Styles="Percent,50,AutoSize,0,Percent,50" /><Rows Styles="Percent,50" /></TableLayoutSettings> + + + Bottom, Left, Right + + + NoControl + + + 248, 0 + + + No + + + 216, 14 + + + 5 + + + &Properties: + + + propertiesLabel + + + System.Windows.Forms.Label, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + overArchingTableLayoutPanel + + + 2 + + + Top, Bottom, Left, Right + + + False + + + 248, 17 + + + 209, 223 + + + 6 + + + propertyBrowser + + + WindowsApplication2.VsPropertyGrid, WindowsApplication2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null + + + overArchingTableLayoutPanel + + + 5 + + + Right + + + True + + + 2 + + + Left, Right + + + True + + + NoControl + + + 3, 3 + + + No + + + 75, 23 + + + 0 + + + OK + + + okButton + + + System.Windows.Forms.Button, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + okCancelTableLayoutPanel + + + 0 + + + Left, Right + + + True + + + NoControl + + + 97, 3 + + + No + + + 75, 23 + + + 1 + + + Cancel + + + cancelButton + + + System.Windows.Forms.Button, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + okCancelTableLayoutPanel + + + 1 + + + 302, 278 + + + 1 + + + 162, 29 + + + 7 + + + okCancelTableLayoutPanel + + + System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + overArchingTableLayoutPanel + + + 6 + + + <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="okButton" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="cancelButton" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /></Controls><Columns Styles="Percent,50,Percent,50" /><Rows Styles="Percent,50" /></TableLayoutSettings> + + + Move Up + + + Bottom, Left + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAEdJREFUOE9jYBj0 + 4MCBA//JdiRU83+yDIFpBtoOcgFphqBrJskQXJqJMoSQZqIMgYU4RWEAMmQYGADzBsgrZCUkspMv3TUC + AGYzbEaI9u+YAAAAAElFTkSuQmCC + + + + NoControl + + + 198, 17 + + + 3, 3, 18, 3 + + + No + + + 24, 24 + + + 3 + + + upButton + + + System.Windows.Forms.Button, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + overArchingTableLayoutPanel + + + 7 + + + 12, 12 + + + 5 + + + 467, 310 + + + 0 + + + overArchingTableLayoutPanel + + + System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 0 + + + <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="downButton" Row="2" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="addRemoveTableLayoutPanel" Row="3" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="propertiesLabel" Row="0" RowSpan="1" Column="2" ColumnSpan="1" /><Control Name="membersLabel" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="listbox" Row="1" RowSpan="2" Column="0" ColumnSpan="1" /><Control Name="propertyBrowser" Row="1" RowSpan="3" Column="2" ColumnSpan="1" /><Control Name="okCancelTableLayoutPanel" Row="4" RowSpan="1" Column="0" ColumnSpan="3" /><Control Name="upButton" Row="1" RowSpan="1" Column="1" ColumnSpan="1" /></Controls><Columns Styles="AutoSize,0,AutoSize,0,Percent,100,Absolute,20" /><Rows Styles="AutoSize,0,AutoSize,0,Percent,100,AutoSize,0,AutoSize,0" /></TableLayoutSettings> + + + 186, 212 + + + 1 + + + listbox + + + WindowsApplication2.FilterListBox, WindowsApplication2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null + + + overArchingTableLayoutPanel + + + 4 + + + True + + + 6, 13 + + + 491, 334 + + + 480, 330 + + + No + + + CenterScreen + + + {0} Collection Editor + + + CollectionEditor + + + System.Windows.Forms.Form, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/System.Windows.Forms.Design.Editors/src/Resources/SR.resx b/src/System.Windows.Forms.Design.Editors/src/Resources/SR.resx index d71f65e236e..3b7a74664c5 100644 --- a/src/System.Windows.Forms.Design.Editors/src/Resources/SR.resx +++ b/src/System.Windows.Forms.Design.Editors/src/Resources/SR.resx @@ -127,4 +127,28 @@ (Unknown) + + The item '{0}' cannot be removed. + + + {0} Collection Editor + + + Read-only component(s) selected. + + + {0} &properties: + + + Multi-Select &Properties: + + + &Properties: + + + Add or remove {0} objects + + + RTL_False + \ No newline at end of file diff --git a/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/CollectionEditor.cs.xlf b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/CollectionEditor.cs.xlf new file mode 100644 index 00000000000..ec1b4df94c4 --- /dev/null +++ b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/CollectionEditor.cs.xlf @@ -0,0 +1,52 @@ + + + + + + {0} Collection Editor + {0} Collection Editor + + + + &Add + &Add + + + + Cancel + Cancel + + + + Move Down + Move Down + + + + &Members: + &Members: + + + + OK + OK + + + + &Properties: + &Properties: + + + + &Remove + &Remove + + + + Move Up + Move Up + + + + + \ No newline at end of file diff --git a/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/CollectionEditor.de.xlf b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/CollectionEditor.de.xlf new file mode 100644 index 00000000000..efb4fbcaeb9 --- /dev/null +++ b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/CollectionEditor.de.xlf @@ -0,0 +1,52 @@ + + + + + + {0} Collection Editor + {0} Collection Editor + + + + &Add + &Add + + + + Cancel + Cancel + + + + Move Down + Move Down + + + + &Members: + &Members: + + + + OK + OK + + + + &Properties: + &Properties: + + + + &Remove + &Remove + + + + Move Up + Move Up + + + + + \ No newline at end of file diff --git a/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/CollectionEditor.es.xlf b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/CollectionEditor.es.xlf new file mode 100644 index 00000000000..47656971a71 --- /dev/null +++ b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/CollectionEditor.es.xlf @@ -0,0 +1,52 @@ + + + + + + {0} Collection Editor + {0} Collection Editor + + + + &Add + &Add + + + + Cancel + Cancel + + + + Move Down + Move Down + + + + &Members: + &Members: + + + + OK + OK + + + + &Properties: + &Properties: + + + + &Remove + &Remove + + + + Move Up + Move Up + + + + + \ No newline at end of file diff --git a/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/CollectionEditor.fr.xlf b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/CollectionEditor.fr.xlf new file mode 100644 index 00000000000..bee64aca350 --- /dev/null +++ b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/CollectionEditor.fr.xlf @@ -0,0 +1,52 @@ + + + + + + {0} Collection Editor + {0} Collection Editor + + + + &Add + &Add + + + + Cancel + Cancel + + + + Move Down + Move Down + + + + &Members: + &Members: + + + + OK + OK + + + + &Properties: + &Properties: + + + + &Remove + &Remove + + + + Move Up + Move Up + + + + + \ No newline at end of file diff --git a/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/CollectionEditor.it.xlf b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/CollectionEditor.it.xlf new file mode 100644 index 00000000000..e8fec5bb771 --- /dev/null +++ b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/CollectionEditor.it.xlf @@ -0,0 +1,52 @@ + + + + + + {0} Collection Editor + {0} Collection Editor + + + + &Add + &Add + + + + Cancel + Cancel + + + + Move Down + Move Down + + + + &Members: + &Members: + + + + OK + OK + + + + &Properties: + &Properties: + + + + &Remove + &Remove + + + + Move Up + Move Up + + + + + \ No newline at end of file diff --git a/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/CollectionEditor.ja.xlf b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/CollectionEditor.ja.xlf new file mode 100644 index 00000000000..02cf37daae8 --- /dev/null +++ b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/CollectionEditor.ja.xlf @@ -0,0 +1,52 @@ + + + + + + {0} Collection Editor + {0} Collection Editor + + + + &Add + &Add + + + + Cancel + Cancel + + + + Move Down + Move Down + + + + &Members: + &Members: + + + + OK + OK + + + + &Properties: + &Properties: + + + + &Remove + &Remove + + + + Move Up + Move Up + + + + + \ No newline at end of file diff --git a/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/CollectionEditor.ko.xlf b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/CollectionEditor.ko.xlf new file mode 100644 index 00000000000..78cd92e0f4a --- /dev/null +++ b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/CollectionEditor.ko.xlf @@ -0,0 +1,52 @@ + + + + + + {0} Collection Editor + {0} Collection Editor + + + + &Add + &Add + + + + Cancel + Cancel + + + + Move Down + Move Down + + + + &Members: + &Members: + + + + OK + OK + + + + &Properties: + &Properties: + + + + &Remove + &Remove + + + + Move Up + Move Up + + + + + \ No newline at end of file diff --git a/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/CollectionEditor.pl.xlf b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/CollectionEditor.pl.xlf new file mode 100644 index 00000000000..024d1af2080 --- /dev/null +++ b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/CollectionEditor.pl.xlf @@ -0,0 +1,52 @@ + + + + + + {0} Collection Editor + {0} Collection Editor + + + + &Add + &Add + + + + Cancel + Cancel + + + + Move Down + Move Down + + + + &Members: + &Members: + + + + OK + OK + + + + &Properties: + &Properties: + + + + &Remove + &Remove + + + + Move Up + Move Up + + + + + \ No newline at end of file diff --git a/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/CollectionEditor.pt-BR.xlf b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/CollectionEditor.pt-BR.xlf new file mode 100644 index 00000000000..633a553271d --- /dev/null +++ b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/CollectionEditor.pt-BR.xlf @@ -0,0 +1,52 @@ + + + + + + {0} Collection Editor + {0} Collection Editor + + + + &Add + &Add + + + + Cancel + Cancel + + + + Move Down + Move Down + + + + &Members: + &Members: + + + + OK + OK + + + + &Properties: + &Properties: + + + + &Remove + &Remove + + + + Move Up + Move Up + + + + + \ No newline at end of file diff --git a/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/CollectionEditor.ru.xlf b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/CollectionEditor.ru.xlf new file mode 100644 index 00000000000..57e11f61e66 --- /dev/null +++ b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/CollectionEditor.ru.xlf @@ -0,0 +1,52 @@ + + + + + + {0} Collection Editor + {0} Collection Editor + + + + &Add + &Add + + + + Cancel + Cancel + + + + Move Down + Move Down + + + + &Members: + &Members: + + + + OK + OK + + + + &Properties: + &Properties: + + + + &Remove + &Remove + + + + Move Up + Move Up + + + + + \ No newline at end of file diff --git a/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/CollectionEditor.tr.xlf b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/CollectionEditor.tr.xlf new file mode 100644 index 00000000000..d5458b8f481 --- /dev/null +++ b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/CollectionEditor.tr.xlf @@ -0,0 +1,52 @@ + + + + + + {0} Collection Editor + {0} Collection Editor + + + + &Add + &Add + + + + Cancel + Cancel + + + + Move Down + Move Down + + + + &Members: + &Members: + + + + OK + OK + + + + &Properties: + &Properties: + + + + &Remove + &Remove + + + + Move Up + Move Up + + + + + \ No newline at end of file diff --git a/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/CollectionEditor.zh-Hans.xlf b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/CollectionEditor.zh-Hans.xlf new file mode 100644 index 00000000000..5f219a55c69 --- /dev/null +++ b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/CollectionEditor.zh-Hans.xlf @@ -0,0 +1,52 @@ + + + + + + {0} Collection Editor + {0} Collection Editor + + + + &Add + &Add + + + + Cancel + Cancel + + + + Move Down + Move Down + + + + &Members: + &Members: + + + + OK + OK + + + + &Properties: + &Properties: + + + + &Remove + &Remove + + + + Move Up + Move Up + + + + + \ No newline at end of file diff --git a/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/CollectionEditor.zh-Hant.xlf b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/CollectionEditor.zh-Hant.xlf new file mode 100644 index 00000000000..db72b6fa279 --- /dev/null +++ b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/CollectionEditor.zh-Hant.xlf @@ -0,0 +1,52 @@ + + + + + + {0} Collection Editor + {0} Collection Editor + + + + &Add + &Add + + + + Cancel + Cancel + + + + Move Down + Move Down + + + + &Members: + &Members: + + + + OK + OK + + + + &Properties: + &Properties: + + + + &Remove + &Remove + + + + Move Up + Move Up + + + + + \ No newline at end of file diff --git a/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.cs.xlf b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.cs.xlf index dc59aec5101..da0a7b75690 100644 --- a/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.cs.xlf +++ b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.cs.xlf @@ -27,6 +27,41 @@ Top + + The item '{0}' cannot be removed. + The item '{0}' cannot be removed. + + + + {0} Collection Editor + {0} Collection Editor + + + + Read-only component(s) selected. + Read-only component(s) selected. + + + + {0} &properties: + {0} &properties: + + + + Multi-Select &Properties: + Multi-Select &Properties: + + + + &Properties: + &Properties: + + + + Add or remove {0} objects + Add or remove {0} objects + + Color Picker Volba barev @@ -97,6 +132,11 @@ Winforms Designer není na této platformě podporován. + + RTL_False + RTL_False + + (Unknown) (Neznámý) diff --git a/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.de.xlf b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.de.xlf index c9882cba10c..95ed6594146 100644 --- a/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.de.xlf +++ b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.de.xlf @@ -27,6 +27,41 @@ Oben + + The item '{0}' cannot be removed. + The item '{0}' cannot be removed. + + + + {0} Collection Editor + {0} Collection Editor + + + + Read-only component(s) selected. + Read-only component(s) selected. + + + + {0} &properties: + {0} &properties: + + + + Multi-Select &Properties: + Multi-Select &Properties: + + + + &Properties: + &Properties: + + + + Add or remove {0} objects + Add or remove {0} objects + + Color Picker Farbauswahl @@ -97,6 +132,11 @@ Der Windows Forms-Designer wird auf dieser Plattform nicht unterstützt. + + RTL_False + RTL_False + + (Unknown) (Unbekannt) diff --git a/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.es.xlf b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.es.xlf index c23932f165d..af0491c66b9 100644 --- a/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.es.xlf +++ b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.es.xlf @@ -27,6 +27,41 @@ Parte superior + + The item '{0}' cannot be removed. + The item '{0}' cannot be removed. + + + + {0} Collection Editor + {0} Collection Editor + + + + Read-only component(s) selected. + Read-only component(s) selected. + + + + {0} &properties: + {0} &properties: + + + + Multi-Select &Properties: + Multi-Select &Properties: + + + + &Properties: + &Properties: + + + + Add or remove {0} objects + Add or remove {0} objects + + Color Picker Selector de color @@ -97,6 +132,11 @@ Winforms Designer no se admite en esta plataforma. + + RTL_False + RTL_False + + (Unknown) (Se desconoce) diff --git a/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.fr.xlf b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.fr.xlf index 80db2ee9e6e..34bca2012c6 100644 --- a/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.fr.xlf +++ b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.fr.xlf @@ -27,6 +27,41 @@ Haut + + The item '{0}' cannot be removed. + The item '{0}' cannot be removed. + + + + {0} Collection Editor + {0} Collection Editor + + + + Read-only component(s) selected. + Read-only component(s) selected. + + + + {0} &properties: + {0} &properties: + + + + Multi-Select &Properties: + Multi-Select &Properties: + + + + &Properties: + &Properties: + + + + Add or remove {0} objects + Add or remove {0} objects + + Color Picker Sélecteur de couleurs @@ -97,6 +132,11 @@ Le concepteur WinForms n'est pas pris en charge sur cette plateforme. + + RTL_False + RTL_False + + (Unknown) (Inconnu) diff --git a/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.it.xlf b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.it.xlf index 1b958a4178a..d8b55db54b4 100644 --- a/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.it.xlf +++ b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.it.xlf @@ -27,6 +27,41 @@ Alto + + The item '{0}' cannot be removed. + The item '{0}' cannot be removed. + + + + {0} Collection Editor + {0} Collection Editor + + + + Read-only component(s) selected. + Read-only component(s) selected. + + + + {0} &properties: + {0} &properties: + + + + Multi-Select &Properties: + Multi-Select &Properties: + + + + &Properties: + &Properties: + + + + Add or remove {0} objects + Add or remove {0} objects + + Color Picker Selezione colori @@ -97,6 +132,11 @@ Winforms Designer non è supportato in questa piattaforma. + + RTL_False + RTL_False + + (Unknown) (Sconosciuto) diff --git a/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.ja.xlf b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.ja.xlf index 2012b7d6dc9..66fd1669845 100644 --- a/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.ja.xlf +++ b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.ja.xlf @@ -27,6 +27,41 @@ + + The item '{0}' cannot be removed. + The item '{0}' cannot be removed. + + + + {0} Collection Editor + {0} Collection Editor + + + + Read-only component(s) selected. + Read-only component(s) selected. + + + + {0} &properties: + {0} &properties: + + + + Multi-Select &Properties: + Multi-Select &Properties: + + + + &Properties: + &Properties: + + + + Add or remove {0} objects + Add or remove {0} objects + + Color Picker カラー ピッカー @@ -97,6 +132,11 @@ Windows フォーム デザイナーは、このプラットフォームではサポートされていません。 + + RTL_False + RTL_False + + (Unknown) (不明) diff --git a/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.ko.xlf b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.ko.xlf index 5f90114df43..4f73c3eae86 100644 --- a/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.ko.xlf +++ b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.ko.xlf @@ -27,6 +27,41 @@ Top + + The item '{0}' cannot be removed. + The item '{0}' cannot be removed. + + + + {0} Collection Editor + {0} Collection Editor + + + + Read-only component(s) selected. + Read-only component(s) selected. + + + + {0} &properties: + {0} &properties: + + + + Multi-Select &Properties: + Multi-Select &Properties: + + + + &Properties: + &Properties: + + + + Add or remove {0} objects + Add or remove {0} objects + + Color Picker 색 선택 @@ -97,6 +132,11 @@ Winforms 디자이너는 이 플랫폼에서 지원되지 않습니다. + + RTL_False + RTL_False + + (Unknown) (알 수 없음) diff --git a/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.pl.xlf b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.pl.xlf index d3105e53d5f..af28a3111e0 100644 --- a/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.pl.xlf +++ b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.pl.xlf @@ -27,6 +27,41 @@ Góra + + The item '{0}' cannot be removed. + The item '{0}' cannot be removed. + + + + {0} Collection Editor + {0} Collection Editor + + + + Read-only component(s) selected. + Read-only component(s) selected. + + + + {0} &properties: + {0} &properties: + + + + Multi-Select &Properties: + Multi-Select &Properties: + + + + &Properties: + &Properties: + + + + Add or remove {0} objects + Add or remove {0} objects + + Color Picker Selektor kolorów @@ -97,6 +132,11 @@ Projektant formularzy systemu Windows nie jest obsługiwany na tej platformie. + + RTL_False + RTL_False + + (Unknown) (Nieznany) diff --git a/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.pt-BR.xlf b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.pt-BR.xlf index 480e26b7d7d..81ebc562226 100644 --- a/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.pt-BR.xlf +++ b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.pt-BR.xlf @@ -27,6 +27,41 @@ Top + + The item '{0}' cannot be removed. + The item '{0}' cannot be removed. + + + + {0} Collection Editor + {0} Collection Editor + + + + Read-only component(s) selected. + Read-only component(s) selected. + + + + {0} &properties: + {0} &properties: + + + + Multi-Select &Properties: + Multi-Select &Properties: + + + + &Properties: + &Properties: + + + + Add or remove {0} objects + Add or remove {0} objects + + Color Picker Selecionador de Cores @@ -97,6 +132,11 @@ O Designer de Formulários do Windows não é compatível com esta plataforma. + + RTL_False + RTL_False + + (Unknown) (Desconhecido) diff --git a/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.ru.xlf b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.ru.xlf index 3edd617a420..1397f7b851b 100644 --- a/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.ru.xlf +++ b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.ru.xlf @@ -27,6 +27,41 @@ По верхнему краю + + The item '{0}' cannot be removed. + The item '{0}' cannot be removed. + + + + {0} Collection Editor + {0} Collection Editor + + + + Read-only component(s) selected. + Read-only component(s) selected. + + + + {0} &properties: + {0} &properties: + + + + Multi-Select &Properties: + Multi-Select &Properties: + + + + &Properties: + &Properties: + + + + Add or remove {0} objects + Add or remove {0} objects + + Color Picker Палитра цветов @@ -97,6 +132,11 @@ Конструктор Windows Forms не поддерживается на этой платформе. + + RTL_False + RTL_False + + (Unknown) (Неизвестный) diff --git a/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.tr.xlf b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.tr.xlf index 9ba014178cd..1e19d22dc44 100644 --- a/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.tr.xlf +++ b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.tr.xlf @@ -27,6 +27,41 @@ Üst + + The item '{0}' cannot be removed. + The item '{0}' cannot be removed. + + + + {0} Collection Editor + {0} Collection Editor + + + + Read-only component(s) selected. + Read-only component(s) selected. + + + + {0} &properties: + {0} &properties: + + + + Multi-Select &Properties: + Multi-Select &Properties: + + + + &Properties: + &Properties: + + + + Add or remove {0} objects + Add or remove {0} objects + + Color Picker Renk Seçici @@ -97,6 +132,11 @@ Winforms Tasarımcısı bu platformda desteklenmiyor. + + RTL_False + RTL_False + + (Unknown) (Bilinmiyor) diff --git a/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.zh-Hans.xlf b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.zh-Hans.xlf index 4f9c91e9576..dc9bf86c6d6 100644 --- a/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.zh-Hans.xlf +++ b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.zh-Hans.xlf @@ -27,6 +27,41 @@ 顶部 + + The item '{0}' cannot be removed. + The item '{0}' cannot be removed. + + + + {0} Collection Editor + {0} Collection Editor + + + + Read-only component(s) selected. + Read-only component(s) selected. + + + + {0} &properties: + {0} &properties: + + + + Multi-Select &Properties: + Multi-Select &Properties: + + + + &Properties: + &Properties: + + + + Add or remove {0} objects + Add or remove {0} objects + + Color Picker 颜色选取器 @@ -97,6 +132,11 @@ 此平台上不支持 Winforms Designer。 + + RTL_False + RTL_False + + (Unknown) (未知) diff --git a/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.zh-Hant.xlf b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.zh-Hant.xlf index 5361d55cea3..812c4ac988d 100644 --- a/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.zh-Hant.xlf +++ b/src/System.Windows.Forms.Design.Editors/src/Resources/xlf/SR.zh-Hant.xlf @@ -27,6 +27,41 @@ + + The item '{0}' cannot be removed. + The item '{0}' cannot be removed. + + + + {0} Collection Editor + {0} Collection Editor + + + + Read-only component(s) selected. + Read-only component(s) selected. + + + + {0} &properties: + {0} &properties: + + + + Multi-Select &Properties: + Multi-Select &Properties: + + + + &Properties: + &Properties: + + + + Add or remove {0} objects + Add or remove {0} objects + + Color Picker 色彩選擇器 @@ -97,6 +132,11 @@ 此平台不支援 WinForms Designer。 + + RTL_False + RTL_False + + (Unknown) (未知) diff --git a/src/System.Windows.Forms.Design.Editors/src/System.Windows.Forms.Design.Editors.csproj b/src/System.Windows.Forms.Design.Editors/src/System.Windows.Forms.Design.Editors.csproj index 11aacc58769..df9698dc3e3 100644 --- a/src/System.Windows.Forms.Design.Editors/src/System.Windows.Forms.Design.Editors.csproj +++ b/src/System.Windows.Forms.Design.Editors/src/System.Windows.Forms.Design.Editors.csproj @@ -9,7 +9,12 @@ true - System.Windows.Forms.Design.Editors.Resources + System + + + + + System.ComponentModel.Design @@ -19,6 +24,9 @@ + + + diff --git a/src/System.Windows.Forms.Design.Editors/src/System/ComponentModel/Design/CollectionEditor.cs b/src/System.Windows.Forms.Design.Editors/src/System/ComponentModel/Design/CollectionEditor.cs new file mode 100644 index 00000000000..864edb62326 --- /dev/null +++ b/src/System.Windows.Forms.Design.Editors/src/System/ComponentModel/Design/CollectionEditor.cs @@ -0,0 +1,2668 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections; +using System.ComponentModel; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Drawing; +using System.Drawing.Design; +using System.Globalization; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Windows.Forms; +using System.Windows.Forms.Design; +using System.Windows.Forms.VisualStyles; + +namespace System.ComponentModel.Design +{ + /// + /// Provides a generic editor for most any collection. + /// + public class CollectionEditor : UITypeEditor + { + private readonly Type _type; + private Type _collectionItemType; + private Type[] _newItemTypes; + private ITypeDescriptorContext _currentContext; + + private bool _ignoreChangedEvents; + private bool _ignoreChangingEvents; + + /// + /// Useful for derived classes to do processing when cancelling changes + /// + protected virtual void CancelChanges() + { + } + + /// + /// Initializes a new instance of the class using the specified collection type. + /// + public CollectionEditor(Type type) + { + _type = type; + } + + /// + /// Gets or sets the data type of each item in the collection. + /// + protected Type CollectionItemType + { + get + { + if (_collectionItemType == null) + { + _collectionItemType = CreateCollectionItemType(); + } + return _collectionItemType; + } + } + + /// + /// Gets or sets the type of the collection. + /// + protected Type CollectionType + { + get + { + return _type; + } + } + + /// + /// Gets or sets a type descriptor that indicates the current context. + /// + protected ITypeDescriptorContext Context + { + get + { + return _currentContext; + } + } + + /// + /// Gets or sets the available item types that can be created for this collection. + /// + protected Type[] NewItemTypes + { + get + { + if (_newItemTypes == null) + { + _newItemTypes = CreateNewItemTypes(); + } + return _newItemTypes; + } + } + + /// + /// Gets the help topic to display for the dialog help button or pressing F1. Override to display a different help topic. + /// + protected virtual string HelpTopic + { + get + { + return "net.ComponentModel.CollectionEditor"; + } + } + + /// + /// Gets or sets a value indicating whether original members of the collection can be removed. + /// + protected virtual bool CanRemoveInstance(object value) + { + if (value is IComponent comp) + { + // Make sure the component is not being inherited -- we can't delete these! + InheritanceAttribute ia = (InheritanceAttribute)TypeDescriptor.GetAttributes(comp)[typeof(InheritanceAttribute)]; + if (ia != null && ia.InheritanceLevel != InheritanceLevel.NotInherited) + { + return false; + } + } + + return true; + } + + /// + /// Gets or sets a value indicating whether multiple collection members can be selected. + /// + protected virtual bool CanSelectMultipleInstances() + { + return true; + } + + /// + /// Creates a new form to show the current collection. + /// + protected virtual CollectionForm CreateCollectionForm() + { + return new CollectionEditorCollectionForm(this); + } + + /// + /// Creates a new instance of the specified collection item type. + /// + protected virtual object CreateInstance(Type itemType) + { + return CollectionEditor.CreateInstance(itemType, (IDesignerHost)GetService(typeof(IDesignerHost)), null); + } + + /// + /// This Function gets the object from the givem object. The input is an arrayList returned as an Object. + /// The output is a arraylist which contains the individual objects that need to be created. + /// + protected virtual IList GetObjectsFromInstance(object instance) + { + ArrayList ret = new ArrayList + { + instance + }; + return ret; + } + + internal static object CreateInstance(Type itemType, IDesignerHost host, string name) + { + object instance = null; + + if (typeof(IComponent).IsAssignableFrom(itemType)) + { + if (host != null) + { + instance = host.CreateComponent(itemType, (string)name); + + // Set component defaults + if (host != null) + { + if (host.GetDesigner((IComponent)instance) is IComponentInitializer init) + { + init.InitializeNewComponent(null); + } + } + } + } + + if (instance == null) + { + instance = TypeDescriptor.CreateInstance(host, itemType, null, null); + } + + return instance; + } + + + /// + /// Retrieves the display text for the given list item. + /// + protected virtual string GetDisplayText(object value) + { + string text; + + if (value == null) + { + return string.Empty; + } + + PropertyDescriptor prop = TypeDescriptor.GetProperties(value)["Name"]; + if (prop != null && prop.PropertyType == typeof(string)) + { + text = (string)prop.GetValue(value); + if (text != null && text.Length > 0) + { + return text; + } + } + + prop = TypeDescriptor.GetDefaultProperty(CollectionType); + if (prop != null && prop.PropertyType == typeof(string)) + { + text = (string)prop.GetValue(value); + if (text != null && text.Length > 0) + { + return text; + } + } + + text = TypeDescriptor.GetConverter(value).ConvertToString(value); + + if (text == null || text.Length == 0) + { + text = value.GetType().Name; + } + + return text; + } + + /// + /// Gets an instance of the data type this collection contains. + /// + protected virtual Type CreateCollectionItemType() + { + PropertyInfo[] props = TypeDescriptor.GetReflectionType(CollectionType).GetProperties(BindingFlags.Public | BindingFlags.Instance); + + for (int i = 0; i < props.Length; i++) + { + if (props[i].Name.Equals("Item") || props[i].Name.Equals("Items")) + { + return props[i].PropertyType; + } + } + + Debug.Fail("Collection " + CollectionType.FullName + " contains no Item or Items property so we cannot display and edit any values"); + return typeof(object); + } + + /// + /// Gets the data types this collection editor can create. + /// + protected virtual Type[] CreateNewItemTypes() + { + return new Type[] { CollectionItemType }; + } + + /// + /// Destroys the specified instance of the object. + /// + protected virtual void DestroyInstance(object instance) + { + if (instance is IComponent compInstance) + { + IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost)); + if (host != null) + { + host.DestroyComponent(compInstance); + } + else + { + compInstance.Dispose(); + } + } + else + { + if (instance is IDisposable dispInstance) + { + dispInstance.Dispose(); + } + } + } + + /// + /// Edits the specified object value using the editor style provided by . + /// + [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")] + public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) + { + if (provider != null) + { + IWindowsFormsEditorService edSvc = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService)); + if (edSvc != null) + { + _currentContext = context; + + // child modal dialog -launching in System Aware mode + CollectionForm localCollectionForm = DpiHelper.CreateInstanceInSystemAwareContext(() => CreateCollectionForm()); + ITypeDescriptorContext lastContext = _currentContext; + localCollectionForm.EditValue = value; + _ignoreChangingEvents = false; + _ignoreChangedEvents = false; + DesignerTransaction trans = null; + + bool commitChange = true; + IComponentChangeService cs = null; + IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost)); + + try + { + try + { + if (host != null) + { + trans = host.CreateTransaction(string.Format(SR.CollectionEditorUndoBatchDesc, CollectionItemType.Name)); + } + } + catch (CheckoutException cxe) + { + if (cxe == CheckoutException.Canceled) + return value; + + throw cxe; + } + + cs = host != null ? (IComponentChangeService)host.GetService(typeof(IComponentChangeService)) : null; + + if (cs != null) + { + cs.ComponentChanged += new ComponentChangedEventHandler(OnComponentChanged); + cs.ComponentChanging += new ComponentChangingEventHandler(OnComponentChanging); + } + + if (localCollectionForm.ShowEditorDialog(edSvc) == DialogResult.OK) + { + value = localCollectionForm.EditValue; + } + else + { + commitChange = false; + } + } + finally + { + localCollectionForm.EditValue = null; + _currentContext = lastContext; + if (trans != null) + { + if (commitChange) + { + trans.Commit(); + } + else + { + trans.Cancel(); + } + } + + if (cs != null) + { + cs.ComponentChanged -= new ComponentChangedEventHandler(OnComponentChanged); + cs.ComponentChanging -= new ComponentChangingEventHandler(OnComponentChanging); + } + + localCollectionForm.Dispose(); + } + } + } + return value; + } + + /// + /// Gets the editing style of the Edit method. + /// + [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")] + public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) + { + return UITypeEditorEditStyle.Modal; + } + + private bool IsAnyObjectInheritedReadOnly(object[] items) + { + // If the object implements IComponent, and is not sited, check with the inheritance service (if it exists) to see if this is a component + // that is being inherited from another class. + // If it is, then we do not want to place it in the collection editor. If the inheritance service + // chose not to site the component, that indicates it should be hidden from the user. + IInheritanceService inheritanceService = null; + bool isInheritanceServiceInitialized = false; + + foreach (object o in items) + { + if (o is IComponent comp && comp.Site == null) + { + if (!isInheritanceServiceInitialized) + { + isInheritanceServiceInitialized = true; + if (Context != null) + { + inheritanceService = (IInheritanceService)Context.GetService(typeof(IInheritanceService)); + } + } + + if (inheritanceService != null && inheritanceService.GetInheritanceAttribute(comp).Equals(InheritanceAttribute.InheritedReadOnly)) + { + return true; + } + } + } + return false; + } + + /// + /// Converts the specified collection into an array of objects. + /// + protected virtual object[] GetItems(object editValue) + { + if (editValue != null) + { + // We look to see if the value implements ICollection, and if it does, we set through that. + if (editValue is Collections.ICollection) + { + ArrayList list = new ArrayList(); + + Collections.ICollection col = (Collections.ICollection)editValue; + foreach (object o in col) + { + list.Add(o); + } + + object[] values = new object[list.Count]; + list.CopyTo(values, 0); + return values; + } + } + + return Array.Empty(); + } + + /// + /// Gets the requested service, if it is available. + /// + protected object GetService(Type serviceType) + { + if (Context != null) + { + return Context.GetService(serviceType); + } + return null; + } + + /// + /// Reflect any change events to the instance object + /// + private void OnComponentChanged(object sender, ComponentChangedEventArgs e) + { + if (!_ignoreChangedEvents && sender != Context.Instance) + { + _ignoreChangedEvents = true; + Context.OnComponentChanged(); + } + } + + /// + /// Reflect any changed events to the instance object + /// + private void OnComponentChanging(object sender, ComponentChangingEventArgs e) + { + if (!_ignoreChangingEvents && sender != Context.Instance) + { + _ignoreChangingEvents = true; + Context.OnComponentChanging(); + } + } + + /// + /// Removes the item from the column header from the listview column header collection + /// + internal virtual void OnItemRemoving(object item) + { + } + + /// + /// Sets the specified collection to have the specified array of items. + /// + protected virtual object SetItems(object editValue, object[] value) + { + if (editValue != null) + { + // We look to see if the value implements IList, and if it does, we set through that. + Debug.Assert(editValue is Collections.IList, "editValue is not an IList"); + if (editValue is Collections.IList list) + { + list.Clear(); + for (int i = 0; i < value.Length; i++) + { + list.Add(value[i]); + } + } + } + return editValue; + } + + /// + /// Called when the help button is clicked. + /// + protected virtual void ShowHelp() + { + if (GetService(typeof(IHelpService)) is IHelpService helpService) + { + helpService.ShowHelpFromKeyword(HelpTopic); + } + else + { + Debug.Fail("Unable to get IHelpService."); + } + } + + internal class SplitButton : Button + { + private PushButtonState _state; + private const int PushButtonWidth = 14; + private Rectangle _dropDownRectangle = new Rectangle(); + private bool _showSplit = false; + + private static bool s_isScalingInitialized = false; + private const int OFFSET_2PIXELS = 2; + private static int s_offset2X = OFFSET_2PIXELS; + private static int s_offset2Y = OFFSET_2PIXELS; + + public SplitButton() + : base() + { + if (!s_isScalingInitialized) + { + if (DpiHelper.IsScalingRequired) + { + s_offset2X = DpiHelper.LogicalToDeviceUnitsX(OFFSET_2PIXELS); + s_offset2Y = DpiHelper.LogicalToDeviceUnitsY(OFFSET_2PIXELS); + } + s_isScalingInitialized = true; + } + } + + public bool ShowSplit + { + set + { + if (value != _showSplit) + { + _showSplit = value; + Invalidate(); + } + } + } + + private PushButtonState State + { + get + { + return _state; + } + set + { + if (!_state.Equals(value)) + { + _state = value; + Invalidate(); + } + } + } + + public override Size GetPreferredSize(Size proposedSize) + { + Size preferredSize = base.GetPreferredSize(proposedSize); + if (_showSplit && !string.IsNullOrEmpty(Text) && TextRenderer.MeasureText(Text, Font).Width + PushButtonWidth > preferredSize.Width) + { + return preferredSize + new Size(PushButtonWidth, 0); + } + + return preferredSize; + } + + protected override bool IsInputKey(Keys keyData) + { + if (keyData.Equals(Keys.Down) && _showSplit) + { + return true; + } + else + { + return base.IsInputKey(keyData); + } + } + + protected override void OnGotFocus(EventArgs e) + { + if (!_showSplit) + { + base.OnGotFocus(e); + return; + } + + if (!State.Equals(PushButtonState.Pressed) && !State.Equals(PushButtonState.Disabled)) + { + State = PushButtonState.Default; + } + } + + protected override void OnKeyDown(KeyEventArgs kevent) + { + if (kevent.KeyCode.Equals(Keys.Down) && _showSplit) + { + ShowContextMenuStrip(); + } + else + { + // Fix for Dev10 bug 462144. We need to pass the unhandled characters (including Keys.Space) on to base.OnKeyDown when it's not to drop the split menu + base.OnKeyDown(kevent); + } + } + + protected override void OnLostFocus(EventArgs e) + { + if (!_showSplit) + { + base.OnLostFocus(e); + return; + } + if (!State.Equals(PushButtonState.Pressed) && !State.Equals(PushButtonState.Disabled)) + { + State = PushButtonState.Normal; + } + } + + protected override void OnMouseDown(MouseEventArgs e) + { + if (!_showSplit) + { + base.OnMouseDown(e); + return; + } + + if (_dropDownRectangle.Contains(e.Location)) + { + ShowContextMenuStrip(); + } + else + { + State = PushButtonState.Pressed; + } + } + + protected override void OnMouseEnter(EventArgs e) + { + if (!_showSplit) + { + base.OnMouseEnter(e); + return; + } + + if (!State.Equals(PushButtonState.Pressed) && !State.Equals(PushButtonState.Disabled)) + { + State = PushButtonState.Hot; + } + } + + protected override void OnMouseLeave(EventArgs e) + { + if (!_showSplit) + { + base.OnMouseLeave(e); + return; + } + + if (!State.Equals(PushButtonState.Pressed) && !State.Equals(PushButtonState.Disabled)) + { + if (Focused) + { + State = PushButtonState.Default; + } + else + { + State = PushButtonState.Normal; + } + } + } + + protected override void OnMouseUp(MouseEventArgs mevent) + { + if (!_showSplit) + { + base.OnMouseUp(mevent); + return; + } + + if (ContextMenuStrip == null || !ContextMenuStrip.Visible) + { + SetButtonDrawState(); + if (Bounds.Contains(Parent.PointToClient(Cursor.Position)) && !_dropDownRectangle.Contains(mevent.Location)) + { + OnClick(new EventArgs()); + } + } + } + + protected override void OnPaint(PaintEventArgs pevent) + { + base.OnPaint(pevent); + + if (!_showSplit) + { + return; + } + + Graphics g = pevent.Graphics; + Rectangle bounds = new Rectangle(0, 0, Width, Height); + TextFormatFlags formatFlags = TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter; + + ButtonRenderer.DrawButton(g, bounds, State); + + _dropDownRectangle = new Rectangle(bounds.Right - PushButtonWidth - 1, 4, PushButtonWidth, bounds.Height - 8); + + + if (RightToLeft == RightToLeft.Yes) + { + _dropDownRectangle.X = bounds.Left + 1; + + g.DrawLine(SystemPens.ButtonHighlight, bounds.Left + PushButtonWidth, 4, bounds.Left + PushButtonWidth, bounds.Bottom - 4); + g.DrawLine(SystemPens.ButtonHighlight, bounds.Left + PushButtonWidth + 1, 4, bounds.Left + PushButtonWidth + 1, bounds.Bottom - 4); + bounds.Offset(PushButtonWidth, 0); + bounds.Width -= PushButtonWidth; + } + else + { + g.DrawLine(SystemPens.ButtonHighlight, bounds.Right - PushButtonWidth, 4, bounds.Right - PushButtonWidth, bounds.Bottom - 4); + g.DrawLine(SystemPens.ButtonHighlight, bounds.Right - PushButtonWidth - 1, 4, bounds.Right - PushButtonWidth - 1, bounds.Bottom - 4); + bounds.Width -= PushButtonWidth; + } + + PaintArrow(g, _dropDownRectangle); + + // If we dont' use mnemonic, set formatFlag to NoPrefix as this will show ampersand. + if (!UseMnemonic) + { + formatFlags |= TextFormatFlags.NoPrefix; + } + else if (!ShowKeyboardCues) + { + formatFlags |= TextFormatFlags.HidePrefix; + } + + if (!string.IsNullOrEmpty(Text)) + { + TextRenderer.DrawText(g, Text, Font, bounds, SystemColors.ControlText, formatFlags); + } + + if (Focused) + { + bounds.Inflate(-4, -4); + } + } + + private void PaintArrow(Graphics g, Rectangle dropDownRect) + { + Point middle = new Point(Convert.ToInt32(dropDownRect.Left + dropDownRect.Width / 2), Convert.ToInt32(dropDownRect.Top + dropDownRect.Height / 2)); + + //if the width is odd - favor pushing it over one pixel right. + middle.X += (dropDownRect.Width % 2); + + Point[] arrow = new Point[] { + new Point(middle.X - s_offset2X, middle.Y - 1), + new Point(middle.X + s_offset2X + 1, middle.Y - 1), + new Point(middle.X, middle.Y + s_offset2Y) + }; + + g.FillPolygon(SystemBrushes.ControlText, arrow); + } + + private void ShowContextMenuStrip() + { + State = PushButtonState.Pressed; + if (ContextMenuStrip != null) + { + ContextMenuStrip.Closed += new ToolStripDropDownClosedEventHandler(ContextMenuStrip_Closed); + ContextMenuStrip.Show(this, 0, Height); + } + } + + private void ContextMenuStrip_Closed(object sender, ToolStripDropDownClosedEventArgs e) + { + if (sender is ContextMenuStrip cms) + { + cms.Closed -= new ToolStripDropDownClosedEventHandler(ContextMenuStrip_Closed); + } + + SetButtonDrawState(); + } + + private void SetButtonDrawState() + { + if (Bounds.Contains(Parent.PointToClient(Cursor.Position))) + { + State = PushButtonState.Hot; + } + else if (Focused) + { + State = PushButtonState.Default; + } + else + { + State = PushButtonState.Normal; + } + } + } + + /// + /// This is the collection editor's default implementation of a collection form. + /// + private class CollectionEditorCollectionForm : CollectionForm + { + + private const int TEXT_INDENT = 1; + private const int PAINT_WIDTH = 20; + private const int PAINT_INDENT = 26; + private static readonly double s_lOG10 = Math.Log(10); + + private ArrayList _createdItems; + private ArrayList _removedItems; + private ArrayList _originalItems; + + private readonly CollectionEditor _editor; + + private FilterListBox _listbox; + private SplitButton _addButton; + private Button _removeButton; + private Button _cancelButton; + private Button _okButton; + private Button _downButton; + private Button _upButton; + private PropertyGrid _propertyBrowser; + private Label _membersLabel; + private Label _propertiesLabel; + private readonly ContextMenuStrip _addDownMenu; + private TableLayoutPanel _okCancelTableLayoutPanel; + private TableLayoutPanel _overArchingTableLayoutPanel; + private TableLayoutPanel _addRemoveTableLayoutPanel; + + private int _suspendEnabledCount = 0; + + private bool _dirty; + + public CollectionEditorCollectionForm(CollectionEditor editor) : base(editor) + { + _editor = editor; + InitializeComponent(); + if (DpiHelper.IsScalingRequired) + { + DpiHelper.ScaleButtonImageLogicalToDevice(_downButton); + DpiHelper.ScaleButtonImageLogicalToDevice(_upButton); + } + Text = string.Format(SR.CollectionEditorCaption, CollectionItemType.Name); + + HookEvents(); + + Type[] newItemTypes = NewItemTypes; + if (newItemTypes.Length > 1) + { + EventHandler addDownMenuClick = new EventHandler(AddDownMenu_click); + _addButton.ShowSplit = true; + _addDownMenu = new ContextMenuStrip(); + _addButton.ContextMenuStrip = _addDownMenu; + for (int i = 0; i < newItemTypes.Length; i++) + { + _addDownMenu.Items.Add(new TypeMenuItem(newItemTypes[i], addDownMenuClick)); + } + } + AdjustListBoxItemHeight(); + } + + private bool IsImmutable + { + get + { + foreach (ListItem item in _listbox.SelectedItems) + { + Type type = item.Value.GetType(); + + // The type is considered immutable if the converter is defined as requiring a + // create instance or all the properties are read-only. + if (!TypeDescriptor.GetConverter(type).GetCreateInstanceSupported()) + { + foreach (PropertyDescriptor p in TypeDescriptor.GetProperties(type)) + { + if (!p.IsReadOnly) + { + return false; + } + } + } + } + return true; + } + } + + /// + /// Adds a new element to the collection. + /// + private void AddButton_click(object sender, EventArgs e) + { + PerformAdd(); + } + + /// + /// Processes a click of the drop down type menu. This creates a new instance. + /// + private void AddDownMenu_click(object sender, EventArgs e) + { + if (sender is TypeMenuItem typeMenuItem) + { + CreateAndAddInstance(typeMenuItem.ItemType); + } + } + + /// + /// This Function adds the individual objects to the ListBox. + /// + private void AddItems(IList instances) + { + + if (_createdItems == null) + { + _createdItems = new ArrayList(); + } + + _listbox.BeginUpdate(); + try + { + foreach (object instance in instances) + { + if (instance != null) + { + _dirty = true; + _createdItems.Add(instance); + ListItem created = new ListItem(_editor, instance); + _listbox.Items.Add(created); + } + } + } + finally + { + _listbox.EndUpdate(); + } + + if (instances.Count == 1) + { + // optimize for the case where we just added one thing... + UpdateItemWidths(_listbox.Items[_listbox.Items.Count - 1] as ListItem); + } + else + { + UpdateItemWidths(null); + } + + SuspendEnabledUpdates(); + try + { + _listbox.ClearSelected(); + _listbox.SelectedIndex = _listbox.Items.Count - 1; + + object[] items = new object[_listbox.Items.Count]; + for (int i = 0; i < items.Length; i++) + { + items[i] = ((ListItem)_listbox.Items[i]).Value; + } + Items = items; + + //fringe case -- someone changes the edit value which resets the selindex, we should keep the new index. + if (_listbox.Items.Count > 0 && _listbox.SelectedIndex != _listbox.Items.Count - 1) + { + _listbox.ClearSelected(); + _listbox.SelectedIndex = _listbox.Items.Count - 1; + } + } + finally + { + ResumeEnabledUpdates(true); + } + } + + private void AdjustListBoxItemHeight() + { + _listbox.ItemHeight = Font.Height + SystemInformation.BorderSize.Width * 2; + } + + /// + /// Determines whether removal of a specific list item should be permitted. + /// Used to determine enabled/disabled state of the Remove (X) button. + /// Items added after editor was opened may always be removed. + /// Items that existed before editor was opened require a call to CanRemoveInstance. + /// + private bool AllowRemoveInstance(object value) + { + if (_createdItems != null && _createdItems.Contains(value)) + { + return true; + } + else + { + return CanRemoveInstance(value); + } + } + + private int CalcItemWidth(Graphics g, ListItem item) + { + int c = _listbox.Items.Count; + if (c < 2) + { + c = 2; //for c-1 should be greater than zero. + } + + SizeF sizeW = g.MeasureString(c.ToString(CultureInfo.CurrentCulture), _listbox.Font); + + int charactersInNumber = ((int)(Math.Log((double)(c - 1)) / s_lOG10) + 1); + int w = 4 + charactersInNumber * (Font.Height / 2); + + w = Math.Max(w, (int)Math.Ceiling(sizeW.Width)); + w += SystemInformation.BorderSize.Width * 4; + + SizeF size = g.MeasureString(GetDisplayText(item), _listbox.Font); + int pic = 0; + if (item.Editor != null && item.Editor.GetPaintValueSupported()) + { + pic = PAINT_WIDTH + TEXT_INDENT; + } + return (int)Math.Ceiling(size.Width) + w + pic + SystemInformation.BorderSize.Width * 4; + } + + /// + /// Aborts changes made in the editor. + /// + [SuppressMessage("Microsoft.Security", "CA2102:CatchNonClsCompliantExceptionsInGeneralHandlers")] + private void CancelButton_click(object sender, EventArgs e) + { + try + { + + _editor.CancelChanges(); + + if (!CollectionEditable || !_dirty) + { + return; + } + + _dirty = false; + _listbox.Items.Clear(); + + if (_createdItems != null) + { + object[] items = _createdItems.ToArray(); + if (items.Length > 0 && items[0] is IComponent && ((IComponent)items[0]).Site != null) + { + // here we bail now because we don't want to do the "undo" manually, + // we're part of a trasaction, we've added item, the rollback will be + // handled by the undo engine because the component in the collection are sited + // doing it here kills perfs because the undo of the transaction has to rollback the remove and then + // rollback the add. This is useless and is only needed for non sited component or other classes + return; + } + for (int i = 0; i < items.Length; i++) + { + DestroyInstance(items[i]); + } + _createdItems.Clear(); + } + if (_removedItems != null) + { + _removedItems.Clear(); + } + + + // Restore the original contents. Because objects get parented during CreateAndAddInstance, the underlying collection + // gets changed during add, but not other operations. Not all consumers of this dialog can roll back every single change, + // but this will at least roll back the additions, removals and reordering. See ASURT #85470. + if (_originalItems != null && (_originalItems.Count > 0)) + { + object[] items = new object[_originalItems.Count]; + for (int i = 0; i < _originalItems.Count; i++) + { + items[i] = _originalItems[i]; + } + Items = items; + _originalItems.Clear(); + } + else + { + Items = new object[0]; + } + + } + catch (Exception ex) + { + DialogResult = DialogResult.None; + DisplayError(ex); + } + } + + /// + /// Performs a create instance and then adds the instance to the list box. + /// + [SuppressMessage("Microsoft.Security", "CA2102:CatchNonClsCompliantExceptionsInGeneralHandlers")] + private void CreateAndAddInstance(Type type) + { + try + { + object instance = CreateInstance(type); + IList multipleInstance = _editor.GetObjectsFromInstance(instance); + + if (multipleInstance != null) + { + AddItems(multipleInstance); + } + } + catch (Exception e) + { + DisplayError(e); + } + } + + /// + /// Moves the selected item down one. + /// + private void DownButton_click(object sender, EventArgs e) + { + try + { + SuspendEnabledUpdates(); + _dirty = true; + int index = _listbox.SelectedIndex; + if (index == _listbox.Items.Count - 1) + return; + int ti = _listbox.TopIndex; + object itemMove = _listbox.Items[index]; + _listbox.Items[index] = _listbox.Items[index + 1]; + _listbox.Items[index + 1] = itemMove; + + if (ti < _listbox.Items.Count - 1) + _listbox.TopIndex = ti + 1; + + _listbox.ClearSelected(); + _listbox.SelectedIndex = index + 1; + + // enabling/disabling the buttons has moved the focus to the OK button, move it back to the sender + Control ctrlSender = (Control)sender; + + if (ctrlSender.Enabled) + { + ctrlSender.Focus(); + } + } + finally + { + ResumeEnabledUpdates(true); + } + } + + private void CollectionEditor_HelpButtonClicked(object sender, CancelEventArgs e) + { + e.Cancel = true; + _editor.ShowHelp(); + } + + private void Form_HelpRequested(object sender, HelpEventArgs e) + { + _editor.ShowHelp(); + } + + /// + /// Retrieves the display text for the given list item (if any). The item determines its own display text + /// through its ToString() method, which delegates to the GetDisplayText() override on the parent CollectionEditor. + /// This means in theory that the text can change at any time (ie. its not fixed when the item is added to the list). + /// The item returns its display text through ToString() so that the same text will be reported to Accessibility clients. + /// + private string GetDisplayText(ListItem item) + { + return (item == null) ? string.Empty : item.ToString(); + } + + private void HookEvents() + { + _listbox.KeyDown += new KeyEventHandler(Listbox_keyDown); + _listbox.DrawItem += new DrawItemEventHandler(Listbox_drawItem); + _listbox.SelectedIndexChanged += new EventHandler(Listbox_selectedIndexChanged); + _listbox.HandleCreated += new EventHandler(Listbox_handleCreated); + _upButton.Click += new EventHandler(UpButton_click); + _downButton.Click += new EventHandler(DownButton_click); + _propertyBrowser.PropertyValueChanged += new PropertyValueChangedEventHandler(PropertyGrid_propertyValueChanged); + _addButton.Click += new EventHandler(AddButton_click); + _removeButton.Click += new EventHandler(RemoveButton_click); + _okButton.Click += new EventHandler(OKButton_click); + _cancelButton.Click += new EventHandler(CancelButton_click); + HelpButtonClicked += new CancelEventHandler(CollectionEditor_HelpButtonClicked); + HelpRequested += new HelpEventHandler(Form_HelpRequested); + Shown += new EventHandler(Form_Shown); + } + + private void InitializeComponent() + { + ComponentResourceManager resources = new ComponentResourceManager(typeof(CollectionEditor)); + _membersLabel = new Label(); + _listbox = new FilterListBox(); + _upButton = new Button(); + _downButton = new Button(); + _propertiesLabel = new Label(); + _propertyBrowser = new PropertyGrid(); + _addButton = new SplitButton(); + _removeButton = new Button(); + _okButton = new Button(); + _cancelButton = new Button(); + _okCancelTableLayoutPanel = new TableLayoutPanel(); + _overArchingTableLayoutPanel = new TableLayoutPanel(); + _addRemoveTableLayoutPanel = new TableLayoutPanel(); + _okCancelTableLayoutPanel.SuspendLayout(); + _overArchingTableLayoutPanel.SuspendLayout(); + _addRemoveTableLayoutPanel.SuspendLayout(); + SuspendLayout(); + + resources.ApplyResources(_membersLabel, "membersLabel"); + _membersLabel.Margin = new Padding(0, 0, 3, 3); + _membersLabel.Name = "membersLabel"; + + resources.ApplyResources(_listbox, "listbox"); + _listbox.SelectionMode = (CanSelectMultipleInstances() ? SelectionMode.MultiExtended : SelectionMode.One); + _listbox.DrawMode = DrawMode.OwnerDrawFixed; + _listbox.FormattingEnabled = true; + _listbox.Margin = new Padding(0, 3, 3, 3); + _listbox.Name = "listbox"; + _overArchingTableLayoutPanel.SetRowSpan(_listbox, 2); + + resources.ApplyResources(_upButton, "upButton"); + _upButton.Name = "upButton"; + + resources.ApplyResources(_downButton, "downButton"); + _downButton.Name = "downButton"; + + resources.ApplyResources(_propertiesLabel, "propertiesLabel"); + _propertiesLabel.AutoEllipsis = true; + _propertiesLabel.Margin = new Padding(0, 0, 3, 3); + _propertiesLabel.Name = "propertiesLabel"; + + resources.ApplyResources(_propertyBrowser, "propertyBrowser"); + _propertyBrowser.CommandsVisibleIfAvailable = false; + _propertyBrowser.Margin = new Padding(3, 3, 0, 3); + _propertyBrowser.Name = "propertyBrowser"; + _overArchingTableLayoutPanel.SetRowSpan(_propertyBrowser, 3); + + resources.ApplyResources(_addButton, "addButton"); + _addButton.Margin = new Padding(0, 3, 3, 3); + _addButton.Name = "addButton"; + + resources.ApplyResources(_removeButton, "removeButton"); + _removeButton.Margin = new Padding(3, 3, 0, 3); + _removeButton.Name = "removeButton"; + + resources.ApplyResources(_okButton, "okButton"); + _okButton.DialogResult = DialogResult.OK; + _okButton.Margin = new Padding(0, 3, 3, 0); + _okButton.Name = "okButton"; + + resources.ApplyResources(_cancelButton, "cancelButton"); + _cancelButton.DialogResult = DialogResult.Cancel; + _cancelButton.Margin = new Padding(3, 3, 0, 0); + _cancelButton.Name = "cancelButton"; + + resources.ApplyResources(_okCancelTableLayoutPanel, "okCancelTableLayoutPanel"); + _overArchingTableLayoutPanel.SetColumnSpan(_okCancelTableLayoutPanel, 3); + _okCancelTableLayoutPanel.Controls.Add(_okButton, 0, 0); + _okCancelTableLayoutPanel.Controls.Add(_cancelButton, 1, 0); + _okCancelTableLayoutPanel.Margin = new Padding(3, 3, 0, 0); + _okCancelTableLayoutPanel.Name = "okCancelTableLayoutPanel"; + + resources.ApplyResources(_overArchingTableLayoutPanel, "overArchingTableLayoutPanel"); + _overArchingTableLayoutPanel.Controls.Add(_downButton, 1, 2); + _overArchingTableLayoutPanel.Controls.Add(_addRemoveTableLayoutPanel, 0, 3); + _overArchingTableLayoutPanel.Controls.Add(_propertiesLabel, 2, 0); + _overArchingTableLayoutPanel.Controls.Add(_membersLabel, 0, 0); + _overArchingTableLayoutPanel.Controls.Add(_listbox, 0, 1); + _overArchingTableLayoutPanel.Controls.Add(_propertyBrowser, 2, 1); + _overArchingTableLayoutPanel.Controls.Add(_okCancelTableLayoutPanel, 0, 4); + _overArchingTableLayoutPanel.Controls.Add(_upButton, 1, 1); + _overArchingTableLayoutPanel.Name = "overArchingTableLayoutPanel"; + + resources.ApplyResources(_addRemoveTableLayoutPanel, "addRemoveTableLayoutPanel"); + _addRemoveTableLayoutPanel.Controls.Add(_addButton, 0, 0); + _addRemoveTableLayoutPanel.Controls.Add(_removeButton, 2, 0); + _addRemoveTableLayoutPanel.Margin = new Padding(0, 3, 3, 3); + _addRemoveTableLayoutPanel.Name = "addRemoveTableLayoutPanel"; + + AcceptButton = _okButton; + resources.ApplyResources(this, "$this"); + AutoScaleMode = AutoScaleMode.Font; + CancelButton = _cancelButton; + Controls.Add(_overArchingTableLayoutPanel); + HelpButton = true; + MaximizeBox = false; + MinimizeBox = false; + Name = "CollectionEditor"; + ShowIcon = false; + ShowInTaskbar = false; + _okCancelTableLayoutPanel.ResumeLayout(false); + _okCancelTableLayoutPanel.PerformLayout(); + _overArchingTableLayoutPanel.ResumeLayout(false); + _overArchingTableLayoutPanel.PerformLayout(); + _addRemoveTableLayoutPanel.ResumeLayout(false); + _addRemoveTableLayoutPanel.PerformLayout(); + ResumeLayout(false); + } + + private void UpdateItemWidths(ListItem item) + { + // VSWhidbey#384112: Its neither safe nor accurate to perform these width calculations prior to normal listbox handle creation. So we nop in this case now. + if (!_listbox.IsHandleCreated) + { + return; + } + + using (Graphics g = _listbox.CreateGraphics()) + { + int old = _listbox.HorizontalExtent; + + if (item != null) + { + int w = CalcItemWidth(g, item); + if (w > old) + { + _listbox.HorizontalExtent = w; + } + } + else + { + int max = 0; + foreach (ListItem i in _listbox.Items) + { + int w = CalcItemWidth(g, i); + if (w > max) + { + max = w; + } + } + _listbox.HorizontalExtent = max; + } + } + } + + /// + /// This draws a row of the listbox. + /// + private void Listbox_drawItem(object sender, DrawItemEventArgs e) + { + if (e.Index != -1) + { + ListItem item = (ListItem)_listbox.Items[e.Index]; + + Graphics g = e.Graphics; + + int c = _listbox.Items.Count; + int maxC = (c > 1) ? c - 1 : c; + // We add the +4 is a fudge factor... + SizeF sizeW = g.MeasureString(maxC.ToString(CultureInfo.CurrentCulture), _listbox.Font); + + int charactersInNumber = ((int)(Math.Log((double)maxC) / s_lOG10) + 1);// Luckily, this is never called if count = 0 + int w = 4 + charactersInNumber * (Font.Height / 2); + + w = Math.Max(w, (int)Math.Ceiling(sizeW.Width)); + w += SystemInformation.BorderSize.Width * 4; + + Rectangle button = new Rectangle(e.Bounds.X, e.Bounds.Y, w, e.Bounds.Height); + + ControlPaint.DrawButton(g, button, ButtonState.Normal); + button.Inflate(-SystemInformation.BorderSize.Width * 2, -SystemInformation.BorderSize.Height * 2); + + int offset = w; + + Color backColor = SystemColors.Window; + Color textColor = SystemColors.WindowText; + if ((e.State & DrawItemState.Selected) == DrawItemState.Selected) + { + backColor = SystemColors.Highlight; + textColor = SystemColors.HighlightText; + } + Rectangle res = new Rectangle(e.Bounds.X + offset, e.Bounds.Y, + e.Bounds.Width - offset, + e.Bounds.Height); + g.FillRectangle(new SolidBrush(backColor), res); + if ((e.State & DrawItemState.Focus) == DrawItemState.Focus) + { + ControlPaint.DrawFocusRectangle(g, res); + } + offset += 2; + + if (item.Editor != null && item.Editor.GetPaintValueSupported()) + { + Rectangle baseVar = new Rectangle(e.Bounds.X + offset, e.Bounds.Y + 1, PAINT_WIDTH, e.Bounds.Height - 3); + g.DrawRectangle(SystemPens.ControlText, baseVar.X, baseVar.Y, baseVar.Width - 1, baseVar.Height - 1); + baseVar.Inflate(-1, -1); + item.Editor.PaintValue(item.Value, g, baseVar); + offset += PAINT_INDENT + TEXT_INDENT; + } + + StringFormat format = new StringFormat(); + try + { + format.Alignment = StringAlignment.Center; + g.DrawString(e.Index.ToString(CultureInfo.CurrentCulture), Font, SystemBrushes.ControlText, + new Rectangle(e.Bounds.X, e.Bounds.Y, w, e.Bounds.Height), format); + } + + finally + { + if (format != null) + { + format.Dispose(); + } + } + + Brush textBrush = new SolidBrush(textColor); + + string itemText = GetDisplayText(item); + + try + { + g.DrawString(itemText, Font, textBrush, new Rectangle(e.Bounds.X + offset, e.Bounds.Y, e.Bounds.Width - offset, e.Bounds.Height)); + } + + finally + { + if (textBrush != null) + { + textBrush.Dispose(); + } + } + + // Check to see if we need to change the horizontal extent of the listbox + int width = offset + (int)g.MeasureString(itemText, Font).Width; + if (width > e.Bounds.Width && _listbox.HorizontalExtent < width) + { + _listbox.HorizontalExtent = width; + } + } + } + + /// + /// Handles keypress events for the list box. + /// + private void Listbox_keyDown(object sender, KeyEventArgs kevent) + { + switch (kevent.KeyData) + { + case Keys.Delete: + PerformRemove(); + break; + case Keys.Insert: + PerformAdd(); + break; + } + } + + /// + /// Event that fires when the selected list box index changes. + /// + private void Listbox_selectedIndexChanged(object sender, EventArgs e) + { + UpdateEnabled(); + } + + /// + /// Event that fires when the list box's window handle is created. + /// + private void Listbox_handleCreated(object sender, EventArgs e) + { + // VSWhidbey#384112: Since we no longer perform width calculations prior to handle + // creation now, we need to ensure we do it at least once after handle creation. + UpdateItemWidths(null); + } + + /// + /// Commits the changes to the editor. + /// + [SuppressMessage("Microsoft.Security", "CA2102:CatchNonClsCompliantExceptionsInGeneralHandlers")] + private void OKButton_click(object sender, EventArgs e) + { + try + { + + if (!_dirty || !CollectionEditable) + { + _dirty = false; + DialogResult = DialogResult.Cancel; + return; + } + + if (_dirty) + { + object[] items = new object[_listbox.Items.Count]; + for (int i = 0; i < items.Length; i++) + { + items[i] = ((ListItem)_listbox.Items[i]).Value; + } + + Items = items; + } + + if (_removedItems != null && _dirty) + { + object[] deadItems = _removedItems.ToArray(); + + for (int i = 0; i < deadItems.Length; i++) + { + DestroyInstance(deadItems[i]); + } + _removedItems.Clear(); + } + if (_createdItems != null) + { + _createdItems.Clear(); + } + + if (_originalItems != null) + { + _originalItems.Clear(); + } + + _listbox.Items.Clear(); + _dirty = false; + } + catch (Exception ex) + { + DialogResult = DialogResult.None; + DisplayError(ex); + } + } + + /// + /// Reflect any change events to the instance object + /// + private void OnComponentChanged(object sender, ComponentChangedEventArgs e) + { + // see if this is any of the items in our list...this can happen if we launched a child editor + if (!_dirty && _originalItems != null) + { + foreach (object item in _originalItems) + { + if (item == e.Component) + { + _dirty = true; + break; + } + } + } + + } + + /// + /// This is called when the value property in the CollectionForm has changed. + /// In it you should update your user interface to reflect the current value. + /// + protected override void OnEditValueChanged() + { + if (!Visible) + { + return; + } + + // Remember these contents for cancellation + if (_originalItems == null) + { + _originalItems = new ArrayList(); + } + _originalItems.Clear(); + + // Now update the list box. + _listbox.Items.Clear(); + _propertyBrowser.Site = new PropertyGridSite(Context, _propertyBrowser); + if (EditValue != null) + { + SuspendEnabledUpdates(); + try + { + object[] items = Items; + for (int i = 0; i < items.Length; i++) + { + _listbox.Items.Add(new ListItem(_editor, items[i])); + _originalItems.Add(items[i]); + } + if (_listbox.Items.Count > 0) + { + _listbox.SelectedIndex = 0; + } + } + finally + { + ResumeEnabledUpdates(true); + } + } + else + { + UpdateEnabled(); + } + + AdjustListBoxItemHeight(); + UpdateItemWidths(null); + + } + + protected override void OnFontChanged(EventArgs e) + { + base.OnFontChanged(e); + AdjustListBoxItemHeight(); + } + + /// + /// Performs the actual add of new items. This is invoked by the add button as well as the insert key on the list box. + /// + private void PerformAdd() + { + CreateAndAddInstance(NewItemTypes[0]); + } + + /// + /// Performs a remove by deleting all items currently selected in the list box. + /// This is called by the delete button as well as the delete key on the list box. + /// + private void PerformRemove() + { + int index = _listbox.SelectedIndex; + + if (index != -1) + { + SuspendEnabledUpdates(); + try + { + if (_listbox.SelectedItems.Count > 1) + { + ArrayList toBeDeleted = new ArrayList(_listbox.SelectedItems); + foreach (ListItem item in toBeDeleted) + { + RemoveInternal(item); + } + } + else + { + RemoveInternal((ListItem)_listbox.SelectedItem); + } + if (index < _listbox.Items.Count) + { + _listbox.SelectedIndex = index; + } + else if (_listbox.Items.Count > 0) + { + _listbox.SelectedIndex = _listbox.Items.Count - 1; + } + } + finally + { + ResumeEnabledUpdates(true); + } + } + } + + /// + /// When something in the properties window changes, we update pertinent text here. + /// + private void PropertyGrid_propertyValueChanged(object sender, PropertyValueChangedEventArgs e) + { + + _dirty = true; + + // Refresh selected listbox item so that it picks up any name change + SuspendEnabledUpdates(); + try + { + int selectedItem = _listbox.SelectedIndex; + if (selectedItem >= 0) + { + _listbox.RefreshItem(_listbox.SelectedIndex); + } + } + finally + { + ResumeEnabledUpdates(false); + } + + // if a property changes, invalidate the grid in case it affects the item's name. + UpdateItemWidths(null); + _listbox.Invalidate(); + + // also update the string above the grid. + _propertiesLabel.Text = string.Format(SR.CollectionEditorProperties, GetDisplayText((ListItem)_listbox.SelectedItem)); + } + + /// + /// Used to actually remove the items, one by one. + /// + [SuppressMessage("Microsoft.Security", "CA2102:CatchNonClsCompliantExceptionsInGeneralHandlers")] + private void RemoveInternal(ListItem item) + { + if (item != null) + { + + _editor.OnItemRemoving(item.Value); + + _dirty = true; + + if (_createdItems != null && _createdItems.Contains(item.Value)) + { + DestroyInstance(item.Value); + _createdItems.Remove(item.Value); + _listbox.Items.Remove(item); + } + else + { + try + { + if (CanRemoveInstance(item.Value)) + { + if (_removedItems == null) + { + _removedItems = new ArrayList(); + } + _removedItems.Add(item.Value); + _listbox.Items.Remove(item); + } + else + { + throw new Exception(string.Format(SR.CollectionEditorCantRemoveItem, GetDisplayText(item))); + } + } + catch (Exception ex) + { + DisplayError(ex); + } + } + UpdateItemWidths(null); + } + } + + /// + /// Removes the selected item. + /// + private void RemoveButton_click(object sender, EventArgs e) + { + PerformRemove(); + + // enabling/disabling the buttons has moved the focus to the OK button, move it back to the sender + Control ctrlSender = (Control)sender; + if (ctrlSender.Enabled) + { + ctrlSender.Focus(); + } + } + + /// + /// used to prevent flicker when playing with the list box selection call resume when done. + /// Calls to UpdateEnabled will return silently until Resume is called + /// + private void ResumeEnabledUpdates(bool updateNow) + { + _suspendEnabledCount--; + + Debug.Assert(_suspendEnabledCount >= 0, "Mismatch suspend/resume enabled"); + + if (updateNow) + { + UpdateEnabled(); + } + else + { + BeginInvoke(new MethodInvoker(UpdateEnabled)); + } + } + /// + /// used to prevent flicker when playing with the list box selection call resume when done. + /// Calls to UpdateEnabled will return silently until Resume is called + /// + private void SuspendEnabledUpdates() + { + _suspendEnabledCount++; + } + + /// + /// Called to show the dialog via the IWindowsFormsEditorService + /// + protected internal override DialogResult ShowEditorDialog(IWindowsFormsEditorService edSvc) + { + IComponentChangeService cs = null; + DialogResult result = DialogResult.OK; + try + { + + cs = (IComponentChangeService)_editor.Context.GetService(typeof(IComponentChangeService)); + + if (cs != null) + { + cs.ComponentChanged += new ComponentChangedEventHandler(OnComponentChanged); + } + + // This is cached across requests, so reset the initial focus. + ActiveControl = _listbox; + //SystemEvents.UserPreferenceChanged += new UserPreferenceChangedEventHandler(this.OnSysColorChange); + result = base.ShowEditorDialog(edSvc); + //SystemEvents.UserPreferenceChanged -= new UserPreferenceChangedEventHandler(this.OnSysColorChange); + } + finally + { + if (cs != null) + { + cs.ComponentChanged -= new ComponentChangedEventHandler(OnComponentChanged); + } + } + return result; + } + + /// + /// Moves an item up one in the list box. + /// + private void UpButton_click(object sender, EventArgs e) + { + int index = _listbox.SelectedIndex; + if (index == 0) + return; + + _dirty = true; + try + { + SuspendEnabledUpdates(); + int ti = _listbox.TopIndex; + object itemMove = _listbox.Items[index]; + _listbox.Items[index] = _listbox.Items[index - 1]; + _listbox.Items[index - 1] = itemMove; + + if (ti > 0) + _listbox.TopIndex = ti - 1; + + _listbox.ClearSelected(); + _listbox.SelectedIndex = index - 1; + + // enabling/disabling the buttons has moved the focus to the OK button, move it back to the sender + Control ctrlSender = (Control)sender; + + if (ctrlSender.Enabled) + { + ctrlSender.Focus(); + } + } + finally + { + ResumeEnabledUpdates(true); + } + + } + + /// + /// Updates the set of enabled buttons. + /// + private void UpdateEnabled() + { + if (_suspendEnabledCount > 0) + { + // We're in the midst of a suspend/resume block Resume should call us back. + return; + } + + bool editEnabled = (_listbox.SelectedItem != null) && CollectionEditable; + _removeButton.Enabled = editEnabled && AllowRemoveInstance(((ListItem)_listbox.SelectedItem).Value); + _upButton.Enabled = editEnabled && _listbox.Items.Count > 1; + _downButton.Enabled = editEnabled && _listbox.Items.Count > 1; + _propertyBrowser.Enabled = editEnabled; + _addButton.Enabled = CollectionEditable; + + if (_listbox.SelectedItem != null) + { + object[] items; + + // If we are to create new instances from the items, then we must wrap them in an outer object. + // otherwise, the user will be presented with a batch of read only properties, which isn't terribly useful. + if (IsImmutable) + { + items = new object[] { new SelectionWrapper(CollectionType, CollectionItemType, _listbox, _listbox.SelectedItems) }; + } + else + { + items = new object[_listbox.SelectedItems.Count]; + for (int i = 0; i < items.Length; i++) + { + items[i] = ((ListItem)_listbox.SelectedItems[i]).Value; + } + } + + int selectedItemCount = _listbox.SelectedItems.Count; + if ((selectedItemCount == 1) || (selectedItemCount == -1)) + { + // handle both single select listboxes and a single item selected in a multi-select listbox + _propertiesLabel.Text = string.Format(SR.CollectionEditorProperties, GetDisplayText((ListItem)_listbox.SelectedItem)); + } + else + { + _propertiesLabel.Text = SR.CollectionEditorPropertiesMultiSelect; + } + + if (_editor.IsAnyObjectInheritedReadOnly(items)) + { + _propertyBrowser.SelectedObjects = null; + _propertyBrowser.Enabled = false; + _removeButton.Enabled = false; + _upButton.Enabled = false; + _downButton.Enabled = false; + _propertiesLabel.Text = SR.CollectionEditorInheritedReadOnlySelection; + } + else + { + _propertyBrowser.Enabled = true; + _propertyBrowser.SelectedObjects = items; + } + } + else + { + _propertiesLabel.Text = SR.CollectionEditorPropertiesNone; + _propertyBrowser.SelectedObject = null; + } + } + + /// + /// When the form is first shown, update controls due to the edit value changes which happened when the form is invisible. + /// + private void Form_Shown(object sender, EventArgs e) + { + OnEditValueChanged(); + } + + /// + /// This class implements a custom type descriptor that is used to provide properties for the set of selected items in the collection editor. + /// It provides a single property that is equivalent to the editor's collection item type. + /// + private class SelectionWrapper : PropertyDescriptor, ICustomTypeDescriptor + { + private readonly Type _collectionType; + private readonly Type _collectionItemType; + private readonly Control _control; + private readonly ICollection _collection; + private readonly PropertyDescriptorCollection _properties; + private object _value; + + public SelectionWrapper(Type collectionType, Type collectionItemType, Control control, ICollection collection) : + base("Value", new Attribute[] { new CategoryAttribute(collectionItemType.Name) }) + { + _collectionType = collectionType; + _collectionItemType = collectionItemType; + _control = control; + _collection = collection; + _properties = new PropertyDescriptorCollection(new PropertyDescriptor[] { this }); + + Debug.Assert(collection.Count > 0, "We should only be wrapped if there is a selection"); + _value = this; + + // In a multiselect case, see if the values are different. If so, NULL our value to represent indeterminate. + foreach (ListItem li in collection) + { + if (_value == this) + { + _value = li.Value; + } + else + { + object nextValue = li.Value; + if (_value != null) + { + if (nextValue == null) + { + _value = null; + break; + } + else + { + if (!_value.Equals(nextValue)) + { + _value = null; + break; + } + } + } + else + { + if (nextValue != null) + { + _value = null; + break; + } + } + } + } + } + + /// + /// When overridden in a derived class, gets the type of the component this property is bound to. + /// + public override Type ComponentType + { + get + { + return _collectionType; + } + } + + /// + /// When overridden in a derived class, gets a value indicating whether this property is read-only. + /// + public override bool IsReadOnly + { + get + { + return false; + } + } + + /// + /// When overridden in a derived class, gets the type of the property. + /// + public override Type PropertyType + { + get + { + return _collectionItemType; + } + } + + /// + /// When overridden in a derived class, indicates whether resetting the will change the value of the . + /// + public override bool CanResetValue(object component) + { + return false; + } + + /// + /// When overridden in a derived class, gets the current value of the property on a component. + /// + public override object GetValue(object component) + { + return _value; + } + + /// + /// When overridden in a derived class, resets the value for this property of the component. + /// + public override void ResetValue(object component) + { + } + + /// + /// When overridden in a derived class, sets the value of the component to a different value. + /// + public override void SetValue(object component, object value) + { + _value = value; + + foreach (ListItem li in _collection) + { + li.Value = value; + } + _control.Invalidate(); + OnValueChanged(component, EventArgs.Empty); + } + + /// + /// When overridden in a derived class, indicates whether the value of this property needs to be persisted. + /// + public override bool ShouldSerializeValue(object component) + { + return false; + } + + /// + /// Retrieves an array of member attributes for the given object. + /// + AttributeCollection ICustomTypeDescriptor.GetAttributes() + { + return TypeDescriptor.GetAttributes(_collectionItemType); + } + + /// + /// Retrieves the class name for this object. If null is returned, the type name is used. + /// + string ICustomTypeDescriptor.GetClassName() + { + return _collectionItemType.Name; + } + + /// + /// Retrieves the name for this object. If null is returned, the default is used. + /// + string ICustomTypeDescriptor.GetComponentName() + { + return null; + } + + /// + /// Retrieves the type converter for this object. + /// + TypeConverter ICustomTypeDescriptor.GetConverter() + { + return null; + } + + /// + /// Retrieves the default event. + /// + EventDescriptor ICustomTypeDescriptor.GetDefaultEvent() + { + return null; + } + + /// + /// Retrieves the default property. + /// + PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty() + { + return this; + } + + /// + /// Retrieves the an editor for this object. + /// + object ICustomTypeDescriptor.GetEditor(Type editorBaseType) + { + return null; + } + + /// + /// Retrieves an array of events that the given component instance provides. + /// This may differ from the set of events the class provides. + /// If the component is sited, the site may add or remove additional events. + /// + EventDescriptorCollection ICustomTypeDescriptor.GetEvents() + { + return EventDescriptorCollection.Empty; + } + + /// + /// Retrieves an array of events that the given component instance provides. + /// This may differ from the set of events the class provides. + /// If the component is sited, the site may add or remove additional events. + /// The returned array of events will be filtered by the given set of attributes. + /// + EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes) + { + return EventDescriptorCollection.Empty; + } + + /// + /// Retrieves an array of properties that the given component instance provides. + /// This may differ from the set of properties the class provides. + /// If the component is sited, the site may add or remove additional properties. + /// + PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties() + { + return _properties; + } + + /// + /// Retrieves an array of properties that the given component instance provides. + /// This may differ from the set of properties the class provides. + /// If the component is sited, the site may add or remove additional properties. + /// The returned array of properties will be filtered by the given set of attributes. + /// + PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes) + { + return _properties; + } + + /// + /// Retrieves the object that directly depends on this value being edited. + /// This is generally the object that is required for the PropertyDescriptor's GetValue and SetValue methods. + /// If 'null' is passed for the PropertyDescriptor, the ICustomComponent descripotor implemementation should return the default object, + /// that is the main object that exposes the properties and attributes + /// + object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd) + { + return this; + } + } + + /// + /// ListItem class. This is a single entry in our list box. It contains the value we're editing as well as accessors for the type converter and UI editor. + /// + private class ListItem + { + private object _value; + private object _uiTypeEditor; + private readonly CollectionEditor _parentCollectionEditor; + + public ListItem(CollectionEditor parentCollectionEditor, object value) + { + _value = value; + _parentCollectionEditor = parentCollectionEditor; + } + + public override string ToString() + { + return _parentCollectionEditor.GetDisplayText(_value); + } + + public UITypeEditor Editor + { + get + { + if (_uiTypeEditor == null) + { + _uiTypeEditor = TypeDescriptor.GetEditor(_value, typeof(UITypeEditor)); + if (_uiTypeEditor == null) + { + _uiTypeEditor = this; + } + } + + if (_uiTypeEditor != this) + { + return (UITypeEditor)_uiTypeEditor; + } + + return null; + } + } + + public object Value + { + get + { + return _value; + } + set + { + _uiTypeEditor = null; + _value = value; + } + } + } + + /// + /// Menu items we attach to the drop down menu if there are multiple types the collection editor can create. + /// + private class TypeMenuItem : ToolStripMenuItem + { + readonly Type _itemType; + + public TypeMenuItem(Type itemType, EventHandler handler) : + base(itemType.Name, null, handler) + { + _itemType = itemType; + } + + public Type ItemType + { + get + { + return _itemType; + } + } + } + } + + /// + /// List box filled with ListItem objects representing the collection. + /// + internal class FilterListBox : ListBox + { + private PropertyGrid _grid; + private Message _lastKeyDown; + + private PropertyGrid PropertyGrid + { + get + { + if (_grid == null) + { + foreach (Control c in Parent.Controls) + { + if (c is PropertyGrid) + { + _grid = (PropertyGrid)c; + break; + } + } + } + return _grid; + } + + } + + // Expose the protected RefreshItem() method so that CollectionEditor can use it + public new void RefreshItem(int index) + { + base.RefreshItem(index); + } + + protected override void WndProc(ref Message m) + { + switch (m.Msg) + { + case NativeMethods.WM_KEYDOWN: + _lastKeyDown = m; + + // the first thing the ime does on a key it cares about is send a VK_PROCESSKEY, so we use that to sling focus to the grid. + if (unchecked((int)(long)m.WParam) == NativeMethods.VK_PROCESSKEY) + { + if (PropertyGrid != null) + { + PropertyGrid.Focus(); + UnsafeNativeMethods.SetFocus(new HandleRef(PropertyGrid, PropertyGrid.Handle)); + Application.DoEvents(); + } + else + { + break; + } + + if (PropertyGrid.Focused || PropertyGrid.ContainsFocus) + { + // recreate the keystroke to the newly activated window + NativeMethods.SendMessage(UnsafeNativeMethods.GetFocus(), NativeMethods.WM_KEYDOWN, _lastKeyDown.WParam, _lastKeyDown.LParam); + } + } + break; + + case NativeMethods.WM_CHAR: + + if ((Control.ModifierKeys & (Keys.Control | Keys.Alt)) != 0) + { + break; + } + + if (PropertyGrid != null) + { + PropertyGrid.Focus(); + UnsafeNativeMethods.SetFocus(new HandleRef(PropertyGrid, PropertyGrid.Handle)); + Application.DoEvents(); + } + else + { + break; + } + + // Make sure we changed focus properly recreate the keystroke to the newly activated window + if (PropertyGrid.Focused || PropertyGrid.ContainsFocus) + { + IntPtr hWnd = UnsafeNativeMethods.GetFocus(); + NativeMethods.SendMessage(hWnd, NativeMethods.WM_KEYDOWN, _lastKeyDown.WParam, _lastKeyDown.LParam); + NativeMethods.SendMessage(hWnd, NativeMethods.WM_CHAR, m.WParam, m.LParam); + return; + } + break; + + } + base.WndProc(ref m); + } + + } + + /// + /// The provides a modal dialog for editing the contents of a collection. + /// + [SuppressMessage("Microsoft.Design", "CA1012:AbstractTypesShouldNotHaveConstructors")] //breaking change + protected abstract class CollectionForm : Form + { + + // Manipulation of the collection. + // + private readonly CollectionEditor _editor; + private object _value; + private short _editableState = EditableDynamic; + + private const short EditableDynamic = 0; + private const short EditableYes = 1; + private const short EditableNo = 2; + + /// + /// Initializes a new instance of the class. + /// + public CollectionForm(CollectionEditor editor) + { + _editor = editor; + } + + /// + /// Gets or sets the data type of each item in the collection. + /// + protected Type CollectionItemType + { + get + { + return _editor.CollectionItemType; + } + } + + /// + /// Gets or sets the type of the collection. + /// + protected Type CollectionType + { + get + { + return _editor.CollectionType; + } + } + + internal virtual bool CollectionEditable + { + get + { + if (_editableState != EditableDynamic) + { + return _editableState == EditableYes; + } + + bool editable = typeof(IList).IsAssignableFrom(_editor.CollectionType); + + if (editable) + { + if (EditValue is IList list) + { + return !list.IsReadOnly; + } + } + return editable; + } + set + { + if (value) + { + _editableState = EditableYes; + } + else + { + _editableState = EditableNo; + } + } + } + + /// + /// Gets or sets a type descriptor that indicates the current context. + /// + protected ITypeDescriptorContext Context + { + get + { + return _editor.Context; + } + } + + /// + /// Gets or sets the value of the item being edited. + /// + public object EditValue + { + get + { + return _value; + } + set + { + _value = value; + OnEditValueChanged(); + } + } + + /// + /// Gets or sets the array of items this form is to display. + /// + protected object[] Items + { + get + { + return _editor.GetItems(EditValue); + } + [SuppressMessage("Microsoft.Security", "CA2102:CatchNonClsCompliantExceptionsInGeneralHandlers")] + set + { + // Request our desire to make a change. + // + bool canChange = false; + try + { + canChange = Context.OnComponentChanging(); + } + catch (Exception ex) + { + if (!ClientUtils.IsCriticalException(ex)) + { + DisplayError(ex); + } + else + { + throw; + } + } + if (canChange) + { + object newValue = _editor.SetItems(EditValue, value); + if (newValue != EditValue) + { + EditValue = newValue; + } + Context.OnComponentChanged(); + } + + } + } + + /// + /// Gets or sets the available item types that can be created for this collection. + /// + protected Type[] NewItemTypes + { + get + { + return _editor.NewItemTypes; + } + } + + /// + /// Gets or sets a value indicating whether original members of the collection can be removed. + /// + protected bool CanRemoveInstance(object value) + { + return _editor.CanRemoveInstance(value); + } + + /// + /// Gets or sets a value indicating whether multiple collection members can be selected. + /// + protected virtual bool CanSelectMultipleInstances() + { + return _editor.CanSelectMultipleInstances(); + } + + /// + /// Creates a new instance of the specified collection item type. + /// + protected object CreateInstance(Type itemType) + { + return _editor.CreateInstance(itemType); + } + + /// + /// Destroys the specified instance of the object. + /// + protected void DestroyInstance(object instance) + { + _editor.DestroyInstance(instance); + } + + /// + /// Displays the given exception to the user. + /// + protected virtual void DisplayError(Exception e) + { + IUIService uis = (IUIService)GetService(typeof(IUIService)); + if (uis != null) + { + uis.ShowError(e); + } + else + { + string message = e.Message; + if (message == null || message.Length == 0) + { + message = e.ToString(); + } + RTLAwareMessageBox.Show(null, message, null, MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1, 0); + } + } + + /// + /// Gets the requested service, if it is available. + /// + protected override object GetService(Type serviceType) + { + return _editor.GetService(serviceType); + } + + /// + /// Called to show the dialog via the IWindowsFormsEditorService + /// + protected internal virtual DialogResult ShowEditorDialog(IWindowsFormsEditorService edSvc) + { + return edSvc.ShowDialog(this); + } + + /// + /// This is called when the value property in the has changed. + /// + protected abstract void OnEditValueChanged(); + } + + internal class PropertyGridSite : ISite + { + + private readonly IServiceProvider _sp; + private readonly IComponent _comp; + private bool _inGetService = false; + + public PropertyGridSite(IServiceProvider sp, IComponent comp) + { + _sp = sp; + _comp = comp; + } + + /// + /// When implemented by a class, gets the component associated with the . + /// + public IComponent Component { get { return _comp; } } + + /// + /// When implemented by a class, gets the container associated with the . + /// + public IContainer Container { get { return null; } } + + /// + /// When implemented by a class, determines whether the component is in design mode. + /// + public bool DesignMode { get { return false; } } + + /// + /// When implemented by a class, gets or sets the name of the component associated with the . + /// + public string Name + { + get { return null; } + set { } + } + + public object GetService(Type t) + { + if (!_inGetService && _sp != null) + { + try + { + _inGetService = true; + return _sp.GetService(t); + } + finally + { + _inGetService = false; + } + } + return null; + } + } + } +} + + diff --git a/src/System.Windows.Forms.Design.Editors/src/System/ComponentModel/Design/ExpandCollapseState.cs b/src/System.Windows.Forms.Design.Editors/src/System/ComponentModel/Design/ExpandCollapseState.cs new file mode 100644 index 00000000000..9c2c1e5a3d9 --- /dev/null +++ b/src/System.Windows.Forms.Design.Editors/src/System/ComponentModel/Design/ExpandCollapseState.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.InteropServices; + +namespace System.Windows.Forms.Design.Editors +{ + [ComVisible(true)] + [Guid("76d12d7e-b227-4417-9ce2-42642ffa896a")] + internal enum ExpandCollapseState + { + Collapsed = 0, + Expanded = 1, + PartiallyExpanded = 2, + LeafNode = 3 + } +} diff --git a/src/System.Windows.Forms.Design.Editors/src/System/ComponentModel/Design/ObjectSelectorEditor.cs b/src/System.Windows.Forms.Design.Editors/src/System/ComponentModel/Design/ObjectSelectorEditor.cs new file mode 100644 index 00000000000..1f16aa9beb9 --- /dev/null +++ b/src/System.Windows.Forms.Design.Editors/src/System/ComponentModel/Design/ObjectSelectorEditor.cs @@ -0,0 +1,355 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; +using System.Drawing.Design; +using System.Runtime.InteropServices; +using System.Windows.Forms; +using System.Windows.Forms.Design; + +namespace System.ComponentModel.Design +{ + [SuppressMessage("Microsoft.Design", "CA1012:AbstractTypesShouldNotHaveConstructors")] + public abstract class ObjectSelectorEditor : UITypeEditor + { + public bool SubObjectSelector = false; + protected object prevValue = null; + protected object currValue = null; + private Selector _selector = null; + + /// + /// Default constructor for ObjectSelectorEditor + /// + public ObjectSelectorEditor() + { + } + + /// + /// Constructor for ObjectSelectorEditor which sets SubObjectSelector equal to parameter subObjectSelector + /// + public ObjectSelectorEditor(bool subObjectSelector) + { + SubObjectSelector = subObjectSelector; + } + + /// + /// Edits the given object value using the editor style + /// provided by ObjectSelectorEditor.GetEditStyle. + /// + [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")] + public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) + { + if (null != provider) + { + IWindowsFormsEditorService edSvc = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService)); + if (edSvc != null) + { + if (null == _selector) + { + _selector = new Selector(this); + + // Enable Vista Explorer treeview style + ApplyTreeViewThemeStyles(_selector); + } + + prevValue = value; + currValue = value; + FillTreeWithData(_selector, context, provider); + _selector.Start(edSvc, value); + edSvc.DropDownControl(_selector); + _selector.Stop(); + if (prevValue != currValue) + { + value = currValue; + } + } + } + + return value; + } + + /// + /// Modify a WinForms TreeView control to use the new Explorer style theme + /// + /// The tree view control to modify + public static void ApplyTreeViewThemeStyles(TreeView treeView) + { + if (treeView == null) + { + throw new ArgumentNullException("treeView"); + } + + treeView.HotTracking = true; + treeView.ShowLines = false; + + IntPtr hwnd = treeView.Handle; + int exstyle = TreeView_GetExtendedStyle(hwnd); + exstyle |= NativeMethods.TVS_EX_DOUBLEBUFFER | NativeMethods.TVS_EX_FADEINOUTEXPANDOS; + TreeView_SetExtendedStyle(hwnd, exstyle, 0); + } + private static int TreeView_GetExtendedStyle(IntPtr handle) + { + IntPtr ptr = NativeMethods.SendMessage(handle, NativeMethods.TVM_GETEXTENDEDSTYLE, IntPtr.Zero, IntPtr.Zero); + return ptr.ToInt32(); + } + + private static void TreeView_SetExtendedStyle(IntPtr handle, int extendedStyle, int mask) + { + NativeMethods.SendMessage(handle, NativeMethods.TVM_SETEXTENDEDSTYLE, new IntPtr(mask), new IntPtr(extendedStyle)); + } + + [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")] // everything in this assembly is full trust. + public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) + { + return UITypeEditorEditStyle.DropDown; + } + + protected internal bool EqualsToValue(object value) + { + if (value == currValue) + return true; + else + return false; + } + + protected virtual void FillTreeWithData(Selector selector, ITypeDescriptorContext context, IServiceProvider provider) + { + selector.Clear(); + } + + // + // override this method to add validation code for new value + // + public virtual void SetValue(object value) + { + currValue = value; + } + + public class Selector : TreeView + { + private readonly ObjectSelectorEditor _editor = null; + private IWindowsFormsEditorService _edSvc = null; + public bool clickSeen = false; + + /// + /// Constructor for Selector, takes ObjectSelectorEditor + /// + public Selector(ObjectSelectorEditor editor) + { + CreateHandle(); + _editor = editor; + + BorderStyle = BorderStyle.None; + FullRowSelect = !editor.SubObjectSelector; + Scrollable = true; + CheckBoxes = false; + ShowPlusMinus = editor.SubObjectSelector; + ShowLines = editor.SubObjectSelector; + ShowRootLines = editor.SubObjectSelector; + + AfterSelect += new TreeViewEventHandler(OnAfterSelect); + } + + /// + /// Adds a Node with given label and value to the parent, provided the parent is not null; + /// Otherwise, adds that node to the Nodes TreeNodeCollection. Returns the new node. + /// + public SelectorNode AddNode(string label, object value, SelectorNode parent) + { + SelectorNode newNode = new SelectorNode(label, value); + + if (parent != null) + { + parent.Nodes.Add(newNode); + } + else + { + Nodes.Add(newNode); + } + return newNode; + } + + /// + /// Returns true if the given node was selected; false otherwise. + /// + private bool ChooseSelectedNodeIfEqual() + { + if (_editor != null && _edSvc != null) + { + _editor.SetValue(((SelectorNode)SelectedNode).value); + if (_editor.EqualsToValue(((SelectorNode)SelectedNode).value)) + { + _edSvc.CloseDropDown(); + return true; + } + } + return false; + } + + /// + /// Clears the TreeNodeCollection and sets clickSeen to false + /// + public void Clear() + { + clickSeen = false; + Nodes.Clear(); + } + + protected void OnAfterSelect(object sender, TreeViewEventArgs e) + { + if (clickSeen) + { + ChooseSelectedNodeIfEqual(); + clickSeen = false; + } + } + + protected override void OnKeyDown(KeyEventArgs e) + { + Keys key = e.KeyCode; + switch (key) + { + case Keys.Return: + if (ChooseSelectedNodeIfEqual()) + { + e.Handled = true; + } + break; + + case Keys.Escape: + _editor.SetValue(_editor.prevValue); + e.Handled = true; + _edSvc.CloseDropDown(); + break; + } + base.OnKeyDown(e); + } + + protected override void OnKeyPress(KeyPressEventArgs e) + { + switch (e.KeyChar) + { + case '\r': // Enter key + e.Handled = true; + break; + } + base.OnKeyPress(e); + } + + protected override void OnNodeMouseClick(TreeNodeMouseClickEventArgs e) + { + // we won't get an OnAfterSelect if it's already selected, so use this instead + if (e.Node == SelectedNode) + { + ChooseSelectedNodeIfEqual(); + } + base.OnNodeMouseClick(e); + } + + /// + /// Sets the selection + /// + public bool SetSelection(object value, TreeNodeCollection nodes) + { + TreeNode[] treeNodes; + + if (nodes == null) + { + treeNodes = new TreeNode[Nodes.Count]; + Nodes.CopyTo(treeNodes, 0); + } + else + { + treeNodes = new TreeNode[nodes.Count]; + nodes.CopyTo(treeNodes, 0); + } + + int len = treeNodes.Length; + if (len == 0) + return false; + + for (int i = 0; i < len; i++) + { + if (((SelectorNode)treeNodes[i]).value == value) + { + SelectedNode = treeNodes[i]; + return true; + } + if ((treeNodes[i].Nodes != null) && (treeNodes[i].Nodes.Count != 0)) + { + treeNodes[i].Expand(); + if (SetSelection(value, treeNodes[i].Nodes)) + { + return true; + } + treeNodes[i].Collapse(); + } + } + return false; + } + + /// + /// Sets the internal IWindowsFormsEditorService to the given edSvc, and calls SetSelection on the given value + /// + public void Start(IWindowsFormsEditorService edSvc, object value) + { + _edSvc = edSvc; + clickSeen = false; + SetSelection(value, Nodes); + } + + /// + /// Sets the internal IWindowsFormsEditorService to null + /// + public void Stop() + { + _edSvc = null; + } + + [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")] // everything in this assembly is full trust. + protected override void WndProc(ref Message m) + { + switch (m.Msg) + { + case NativeMethods.WM_GETDLGCODE: + m.Result = (IntPtr)((long)m.Result | NativeMethods.DLGC_WANTALLKEYS); + return; + case NativeMethods.WM_MOUSEMOVE: + if (clickSeen) + { + clickSeen = false; + } + break; + case NativeMethods.WM_REFLECT + NativeMethods.WM_NOTIFY: + NativeMethods.NMTREEVIEW nmtv = (NativeMethods.NMTREEVIEW)Marshal.PtrToStructure(m.LParam, typeof(NativeMethods.NMTREEVIEW)); + if (nmtv.nmhdr.code == NativeMethods.NM_CLICK) + { + clickSeen = true; + } + break; + } + base.WndProc(ref m); + } + } + + /// Suppressed because although the type implements ISerializable --its on the base class and this class + /// is not modifying the stream to include its local information. Therefore, we should not publicly advertise this as + /// Serializable unless explicitly required. + [SuppressMessage("Microsoft.Usage", "CA2237:MarkISerializableTypesWithSerializable")] + public class SelectorNode : TreeNode + { + public object value = null; + + /// + /// Sets label and value to given. + /// + public SelectorNode(string label, object value) : base(label) + { + this.value = value; + } + } + } +} diff --git a/src/System.Windows.Forms.Design.Editors/src/System/Drawing/Design/BitmapEditor.cs b/src/System.Windows.Forms.Design.Editors/src/System/Drawing/Design/BitmapEditor.cs index 6c25a2b4558..839f66fa0f0 100644 --- a/src/System.Windows.Forms.Design.Editors/src/System/Drawing/Design/BitmapEditor.cs +++ b/src/System.Windows.Forms.Design.Editors/src/System/Drawing/Design/BitmapEditor.cs @@ -2,9 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.Collections.Generic; using System.IO; -using System.Windows.Forms.Design.Editors.Resources; namespace System.Drawing.Design { diff --git a/src/System.Windows.Forms.Design.Editors/src/System/Drawing/Design/ColorEditor.cs b/src/System.Windows.Forms.Design.Editors/src/System/Drawing/Design/ColorEditor.cs index 4125e7a36dd..669e7d7cdf9 100644 --- a/src/System.Windows.Forms.Design.Editors/src/System/Drawing/Design/ColorEditor.cs +++ b/src/System.Windows.Forms.Design.Editors/src/System/Drawing/Design/ColorEditor.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.Collections; using System.ComponentModel; using System.Diagnostics; @@ -12,7 +13,6 @@ using System.Runtime.InteropServices; using System.Windows.Forms; using System.Windows.Forms.Design; -using System.Windows.Forms.Design.Editors.Resources; namespace System.Drawing.Design { diff --git a/src/System.Windows.Forms.Design.Editors/src/System/Drawing/Design/ImageEditor.cs b/src/System.Windows.Forms.Design.Editors/src/System/Drawing/Design/ImageEditor.cs index 44fd0a3a7ca..1d347a9f4fd 100644 --- a/src/System.Windows.Forms.Design.Editors/src/System/Drawing/Design/ImageEditor.cs +++ b/src/System.Windows.Forms.Design.Editors/src/System/Drawing/Design/ImageEditor.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.Collections; using System.ComponentModel; using System.Diagnostics.CodeAnalysis; @@ -10,7 +11,6 @@ using System.Runtime.InteropServices; using System.Windows.Forms; using System.Windows.Forms.Design; -using System.Windows.Forms.Design.Editors.Resources; namespace System.Drawing.Design { diff --git a/src/System.Windows.Forms.Design.Editors/src/System/Drawing/Design/MetafileEditor.cs b/src/System.Windows.Forms.Design.Editors/src/System/Drawing/Design/MetafileEditor.cs index 97f9034d579..125272eed15 100644 --- a/src/System.Windows.Forms.Design.Editors/src/System/Drawing/Design/MetafileEditor.cs +++ b/src/System.Windows.Forms.Design.Editors/src/System/Drawing/Design/MetafileEditor.cs @@ -2,9 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.Drawing.Imaging; using System.IO; -using System.Windows.Forms.Design.Editors.Resources; namespace System.Drawing.Design { diff --git a/src/System.Windows.Forms.Design.Editors/src/System/Windows/Forms/Design/AnchorEditor.cs b/src/System.Windows.Forms.Design.Editors/src/System/Windows/Forms/Design/AnchorEditor.cs index 40d6255ba42..1e6a2be0a02 100644 --- a/src/System.Windows.Forms.Design.Editors/src/System/Windows/Forms/Design/AnchorEditor.cs +++ b/src/System.Windows.Forms.Design.Editors/src/System/Windows/Forms/Design/AnchorEditor.cs @@ -2,11 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.Drawing; using System.Drawing.Design; -using System.Windows.Forms.Design.Editors.Resources; namespace System.Windows.Forms.Design { diff --git a/src/System.Windows.Forms.Design.Editors/src/System/Windows/Forms/Design/DockEditor.cs b/src/System.Windows.Forms.Design.Editors/src/System/Windows/Forms/Design/DockEditor.cs index 406f9b3f649..aabd1278fde 100644 --- a/src/System.Windows.Forms.Design.Editors/src/System/Windows/Forms/Design/DockEditor.cs +++ b/src/System.Windows.Forms.Design.Editors/src/System/Windows/Forms/Design/DockEditor.cs @@ -2,11 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.Drawing; using System.Drawing.Design; -using System.Windows.Forms.Design.Editors.Resources; namespace System.Windows.Forms.Design { diff --git a/src/System.Windows.Forms.Design.Editors/src/System/Windows/Forms/Design/FileNameEditor.cs b/src/System.Windows.Forms.Design.Editors/src/System/Windows/Forms/Design/FileNameEditor.cs index 7c12e247231..ba9202bf67c 100644 --- a/src/System.Windows.Forms.Design.Editors/src/System/Windows/Forms/Design/FileNameEditor.cs +++ b/src/System.Windows.Forms.Design.Editors/src/System/Windows/Forms/Design/FileNameEditor.cs @@ -2,11 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Drawing.Design; -using System.Windows.Forms.Design.Editors.Resources; namespace System.Windows.Forms.Design { diff --git a/src/System.Windows.Forms.Design.Editors/src/System/Windows/Forms/Design/ShortcutKeysEditor.cs b/src/System.Windows.Forms.Design.Editors/src/System/Windows/Forms/Design/ShortcutKeysEditor.cs index 9104ede760c..adc1bf1940a 100644 --- a/src/System.Windows.Forms.Design.Editors/src/System/Windows/Forms/Design/ShortcutKeysEditor.cs +++ b/src/System.Windows.Forms.Design.Editors/src/System/Windows/Forms/Design/ShortcutKeysEditor.cs @@ -2,12 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Drawing; using System.Drawing.Design; -using System.Windows.Forms.Design.Editors.Resources; namespace System.Windows.Forms.Design { diff --git a/src/System.Windows.Forms.Design.Editors/tests/UnitTests/CollectionEditorTests.cs b/src/System.Windows.Forms.Design.Editors/tests/UnitTests/CollectionEditorTests.cs new file mode 100644 index 00000000000..0f7b87bf337 --- /dev/null +++ b/src/System.Windows.Forms.Design.Editors/tests/UnitTests/CollectionEditorTests.cs @@ -0,0 +1,70 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.ComponentModel; +using System.Globalization; +using System.Reflection; +using Xunit; + +namespace System.ComponentModel.Design.Tests +{ + public class CollectionEditorTests + { + [Fact] + public void CollectionEditor_Constructor() + { + var underTest = GetNewEditor(); + Assert.NotNull(underTest); + } + + [Fact] + public void CollectionEditor_Getters() + { + var underTest = GetNewEditor(); + Assert.Equal(typeof(string), underTest.GetCollectionType()); + Assert.True(underTest.CanSelectMultiple()); + Assert.True(underTest.CanRemove("some string")); + Assert.True(underTest.CanRemove(1234)); + Assert.Equal("net.ComponentModel.CollectionEditor", underTest.GetHelpTopic()); + Assert.Equal("my string", underTest.GetItemDisplayText("my string")); + } + + private TestCollectionEditor GetNewEditor() + { + return new TestCollectionEditor(typeof(string)); + } + + private class TestCollectionEditor : CollectionEditor + { + public TestCollectionEditor(Type type) : base(type) + { + } + + public Type GetCollectionType() + { + return base.CollectionType; + } + + public bool CanSelectMultiple() + { + return base.CanSelectMultipleInstances(); + } + + public bool CanRemove(object value) + { + return base.CanRemoveInstance(value); + } + + public string GetHelpTopic() + { + return base.HelpTopic; + } + + public string GetItemDisplayText(object value) + { + return base.GetDisplayText(value); + } + } + } +} diff --git a/src/System.Windows.Forms.Design.Editors/tests/UnitTests/ObjectSelectorEditorTests.cs b/src/System.Windows.Forms.Design.Editors/tests/UnitTests/ObjectSelectorEditorTests.cs new file mode 100644 index 00000000000..648b877f01f --- /dev/null +++ b/src/System.Windows.Forms.Design.Editors/tests/UnitTests/ObjectSelectorEditorTests.cs @@ -0,0 +1,75 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Drawing.Design; +using Xunit; + +namespace System.ComponentModel.Design.Tests +{ + public class ObjectSelectorEditorTests + { + + [Fact] + public void ObjectSelectorEditor_Constructor() + { + var underTest = GetNewObjectSelectorEditor(); + + Assert.NotNull(underTest); + Assert.True(underTest.EqualsToValue(null)); + Assert.False(underTest.SubObjectSelector); + + underTest = GetNewObjectSelectorEditor(true); + Assert.True(underTest.SubObjectSelector); + } + + [Fact] + public void ObjectSelectorEditor_CurrentValue() + { + var underTest = GetNewObjectSelectorEditor(); + + underTest.SetValue("some Value"); + Assert.True(underTest.EqualsToValue("some Value")); + Assert.False(underTest.EqualsToValue("some other value")); + } + + [Fact] + public void ObjectSelectorEditor_GetEditStyle() { + var underTest = GetNewObjectSelectorEditor(); + + Assert.Equal(UITypeEditorEditStyle.DropDown, underTest.GetEditStyle(null)); + } + + [Fact] + public void ObjectSelectorEditor_Selector() + { + var underTest = GetNewSelector(); + + Assert.NotNull(underTest); + underTest.AddNode("node", "value", null); + Assert.Single(underTest.Nodes); + Assert.True(underTest.SetSelection("value", null)); + Assert.False(underTest.SetSelection("other value", null)); + underTest.Clear(); + Assert.Empty(underTest.Nodes); + } + + private ObjectSelectorEditor GetNewObjectSelectorEditor(bool subObjectSelector = false) + { + return subObjectSelector ? new TestObjectSelectorEditor(subObjectSelector) : new TestObjectSelectorEditor(); + } + + private class TestObjectSelectorEditor : ObjectSelectorEditor { + public TestObjectSelectorEditor() + { + } + public TestObjectSelectorEditor(bool subObjectSelector) : base(subObjectSelector) + { + } + } + + private ObjectSelectorEditor.Selector GetNewSelector() { + return new ObjectSelectorEditor.Selector(GetNewObjectSelectorEditor()); + } + } +} diff --git a/src/System.Windows.Forms/src/Resources/SR.resx b/src/System.Windows.Forms/src/Resources/SR.resx index 2f1c2bf2cf8..32502b9f806 100644 --- a/src/System.Windows.Forms/src/Resources/SR.resx +++ b/src/System.Windows.Forms/src/Resources/SR.resx @@ -1,64 +1,5 @@  - diff --git a/src/System.Windows.Forms/src/SR.cs b/src/System.Windows.Forms/src/SR.cs deleted file mode 100644 index da86c88e111..00000000000 --- a/src/System.Windows.Forms/src/SR.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Resources; - -namespace System -{ - internal static partial class SR - { - public static object GetObject(string name) - { - object resourceObject = null; - try { resourceObject = ResourceManager.GetObject(name); } - catch (MissingManifestResourceException) { } - return resourceObject; - } - } -} \ No newline at end of file diff --git a/src/System.Windows.Forms/src/System.Windows.Forms.csproj b/src/System.Windows.Forms/src/System.Windows.Forms.csproj index 64b0e896972..dcf369bd11a 100644 --- a/src/System.Windows.Forms/src/System.Windows.Forms.csproj +++ b/src/System.Windows.Forms/src/System.Windows.Forms.csproj @@ -22,6 +22,9 @@ + + + diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/ListView.cs b/src/System.Windows.Forms/src/System/Windows/Forms/ListView.cs index 6fd67f8a3e0..d55a8fd5e0e 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/ListView.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/ListView.cs @@ -4,22 +4,22 @@ namespace System.Windows.Forms { - using System.Runtime.Serialization.Formatters; - using System.Runtime.InteropServices; - using System.Runtime.Remoting; + using Microsoft.Win32; + using System; + using System.Collections; + using System.Collections.Generic; using System.ComponentModel; + using System.ComponentModel.Design; using System.Diagnostics; - using System; - using System.Drawing.Design; + using System.Diagnostics.CodeAnalysis; using System.Drawing; - using System.Windows.Forms.Internal; - using System.ComponentModel.Design; - using System.Collections; - using Microsoft.Win32; + using System.Drawing.Design; using System.Globalization; + using System.Runtime.InteropServices; + using System.Runtime.Remoting; + using System.Runtime.Serialization.Formatters; + using System.Windows.Forms.Internal; using System.Windows.Forms.Layout; - using System.Collections.Generic; - using System.Diagnostics.CodeAnalysis; using System.Windows.Forms.VisualStyles; /// diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/PropertyGridInternal/GridEntry.cs b/src/System.Windows.Forms/src/System/Windows/Forms/PropertyGridInternal/GridEntry.cs index e3c3de26ed5..02ef1525b01 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/PropertyGridInternal/GridEntry.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/PropertyGridInternal/GridEntry.cs @@ -1292,11 +1292,11 @@ public virtual void DisposeChildren() { internal virtual void EditPropertyValue(PropertyGridView iva) { if (UITypeEditor != null) { try { - // this is another icky part. since edit value can push a modal loop + // Since edit value can push a modal loop // there is a chance that this gridentry will be zombied before - // it returns. make sure we're not disposed. + // it returns. Make sure we're not disposed. // - object originalValue = this.PropertyValue; + object originalValue = PropertyValue; object value = UITypeEditor.EditValue(this, (IServiceProvider)(ITypeDescriptorContext)this, originalValue); if (Disposed) { diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/WinCategoryAttribute.cs b/src/System.Windows.Forms/src/System/Windows/Forms/WinCategoryAttribute.cs index 5156101f7df..5f0881e3b49 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/WinCategoryAttribute.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/WinCategoryAttribute.cs @@ -40,12 +40,20 @@ public WinCategoryAttribute(string category) : base(category) { protected override string GetLocalizedString(string value) { string localizedValue = base.GetLocalizedString(value); if (localizedValue == null) { - localizedValue = (string)SR.GetObject("WinFormsCategory" + value); + localizedValue = (string)GetSRObject("WinFormsCategory" + value); } // This attribute is internal, and we should never have a missing resource string. // Debug.Assert(localizedValue != null, "All Windows Forms category attributes should have localized strings. Category '" + value + "' not found."); return localizedValue; } + + private static object GetSRObject(string name) + { + object resourceObject = null; + try { resourceObject = SR.ResourceManager.GetObject(name); } + catch (System.Resources.MissingManifestResourceException) { } + return resourceObject; + } } } diff --git a/src/System.Windows.Forms/tests/IntegrationTests/System.Windows.Forms.IntegrationTests/TestHelpers.cs b/src/System.Windows.Forms/tests/IntegrationTests/System.Windows.Forms.IntegrationTests/TestHelpers.cs index 86779d0887f..efa922880ae 100644 --- a/src/System.Windows.Forms/tests/IntegrationTests/System.Windows.Forms.IntegrationTests/TestHelpers.cs +++ b/src/System.Windows.Forms/tests/IntegrationTests/System.Windows.Forms.IntegrationTests/TestHelpers.cs @@ -172,6 +172,50 @@ public static bool PressTabOnProcess(Process process) return PressOnProcess(process, "{TAB}"); } + /// + /// Presses Right on the given process if it can be made the foreground process + /// + /// The process to send the Right key to + /// Whether or not the Right key was pressed on the process + /// + public static bool PressRightOnProcess(Process process) + { + return PressOnProcess(process, "{RIGHT}"); + } + + /// + /// Presses Down on the given process if it can be made the foreground process + /// + /// The process to send the Down key to + /// Whether or not the Down key was pressed on the process + /// + public static bool PressDownOnProcess(Process process) + { + return PressOnProcess(process, "{DOWN}"); + } + + /// + /// Presses Left on the given process if it can be made the foreground process + /// + /// The process to send the Left key to + /// Whether or not the Left key was pressed on the process + /// + public static bool PressLeftOnProcess(Process process) + { + return PressOnProcess(process, "{LEFT}"); + } + + /// + /// Presses Up on the given process if it can be made the foreground process + /// + /// The process to send the Up key to + /// Whether or not the Up key was pressed on the process + /// + public static bool PressUpOnProcess(Process process) + { + return PressOnProcess(process, "{UP}"); + } + /// /// Presses Tab any number of times on the given process if it can be made the foreground process /// diff --git a/src/System.Windows.Forms/tests/IntegrationTests/System.Windows.Forms.IntegrationTests/WinformsControlsTest.cs b/src/System.Windows.Forms/tests/IntegrationTests/System.Windows.Forms.IntegrationTests/WinformsControlsTest.cs index 98e4d23764b..b548c785abe 100644 --- a/src/System.Windows.Forms/tests/IntegrationTests/System.Windows.Forms.IntegrationTests/WinformsControlsTest.cs +++ b/src/System.Windows.Forms/tests/IntegrationTests/System.Windows.Forms.IntegrationTests/WinformsControlsTest.cs @@ -219,6 +219,27 @@ public void WinformsControlsTest_PropertyGridTest() Assert.True(process.HasExited); } + [Fact] + public void WinformsControlsTest_PropertyGrid_CollectionEditorTest() + { + var process = TestHelpers.StartProcess(GetPathToTestFromBin()); + TestHelpers.PressTabsOnProcess(process, 11); + TestHelpers.PressEnterOnProcess(process); + + TestHelpers.PressTabOnProcess(process); + TestHelpers.PressRightOnProcess(process); // once + TestHelpers.PressRightOnProcess(process); // twice + TestHelpers.PressTabsOnProcess(process, 2); + TestHelpers.PressEnterOnProcess(process); + + Assert.False(process.HasExited); + + process.Kill(); + process.WaitForExit(); + + Assert.True(process.HasExited); + } + // [Fact] // Commenting this out until this is fixed // public void WinformsControlsTest_ListViewTest() diff --git a/src/System.Windows.Forms/tests/IntegrationTests/WinformsControlsTest/PropertyGrid.Designer.cs b/src/System.Windows.Forms/tests/IntegrationTests/WinformsControlsTest/PropertyGrid.Designer.cs index fd93ad798ed..0d953040934 100644 --- a/src/System.Windows.Forms/tests/IntegrationTests/WinformsControlsTest/PropertyGrid.Designer.cs +++ b/src/System.Windows.Forms/tests/IntegrationTests/WinformsControlsTest/PropertyGrid.Designer.cs @@ -42,7 +42,6 @@ private void InitializeComponent() this.propertyGrid1.Location = new System.Drawing.Point(0, 0); this.propertyGrid1.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); this.propertyGrid1.Name = "propertyGrid1"; - this.propertyGrid1.SelectedObject = this; this.propertyGrid1.Size = new System.Drawing.Size(465, 413); this.propertyGrid1.TabIndex = 0; // @@ -54,7 +53,7 @@ private void InitializeComponent() this.Controls.Add(this.propertyGrid1); this.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); this.Name = "PropertyGrid"; - this.Text = "Form1"; + this.Text = "Property Grid Test"; this.ResumeLayout(false); } @@ -63,4 +62,4 @@ private void InitializeComponent() private System.Windows.Forms.PropertyGrid propertyGrid1; } -} \ No newline at end of file +} diff --git a/src/System.Windows.Forms/tests/IntegrationTests/WinformsControlsTest/PropertyGrid.cs b/src/System.Windows.Forms/tests/IntegrationTests/WinformsControlsTest/PropertyGrid.cs index 2e010c1f87b..6402955cddd 100644 --- a/src/System.Windows.Forms/tests/IntegrationTests/WinformsControlsTest/PropertyGrid.cs +++ b/src/System.Windows.Forms/tests/IntegrationTests/WinformsControlsTest/PropertyGrid.cs @@ -2,13 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.Collections.Generic; using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Text; +using System.Drawing.Design; using System.Windows.Forms; +using System.ComponentModel.Design; +using System.Collections.Generic; +using System; +using System.Globalization; +using System.Text; namespace WinformsControlsTest { @@ -17,6 +18,48 @@ public partial class PropertyGrid : Form public PropertyGrid() { InitializeComponent(); + propertyGrid1.SelectedObject = new UserControlWithObjectCollectionEditor(); + } + } + + internal class UserControlWithObjectCollectionEditor : UserControl + { + public UserControlWithObjectCollectionEditor() + { + AutoScaleMode = AutoScaleMode.Font; + } + + [Editor(typeof(CollectionEditor), typeof(UITypeEditor))] + [Browsable(true)] + [EditorBrowsable(EditorBrowsableState.Always)] + [Category("Accessibility")] + [TypeConverter(typeof(SomeCollectionTypeConverter))] + public IList AAAAAFirstCollection + { + get { return new List(new int[] { 1, 2, 3 }); } + set { } + } + } + + internal class SomeCollectionTypeConverter : TypeConverter + { + public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) + { + if (destinationType != null && destinationType.IsAssignableFrom(typeof(string)) && value != null && value is IList list) + { + var result = new StringBuilder(""); + for (int i = 0; i < list.Count; i++) + { + if (i != 0) + { + result.Append(", "); + } + result.Append(list[i]); + } + return result.ToString(); + } + return base.ConvertTo(context, culture, value, destinationType); } } + } diff --git a/src/System.Windows.Forms/tests/IntegrationTests/WinformsControlsTest/WinformsControlsTest.csproj b/src/System.Windows.Forms/tests/IntegrationTests/WinformsControlsTest/WinformsControlsTest.csproj index a314eaf9f7e..8b450681026 100644 --- a/src/System.Windows.Forms/tests/IntegrationTests/WinformsControlsTest/WinformsControlsTest.csproj +++ b/src/System.Windows.Forms/tests/IntegrationTests/WinformsControlsTest/WinformsControlsTest.csproj @@ -3,12 +3,16 @@ netcoreapp3.0 WinformsControlsTest + WinformsControlsTest + 7.3 WinExe + +