Hallo,
im PropertyGrid kann ich ja mittels den StringCollectionEditor öffnen:
[Editor("System.Windows.Forms.Design.StringCollectionEditor, System.Design, Version=2.0.0.0, Culture=neutral,
typeof(UITypeEditor))]
Ist es auch möglich diesen z.B. per Click-Event zu öffnen?
gruß Franz
Ich habe diesen Code dazu im Internet gefunden, aber nicht ausprobiert:
EDIT: Ich weiss aber nicht mehr wo. Vielleicht reicht das ja schon aus?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace StringCollectionEditorTest
{
/// <include file="doc\StringCollectionEditor.uex" path="docs/doc[@for="StringCollectionEditor"]/*">
/// <devdoc>
/// The StringCollectionEditor is a collection editor that is specifically
/// designed to edit collections containing strings. The collection can be
/// of any type that can accept a string value; we just present a string-centric
/// dialog for the user.
/// </devdoc>
public class StringCollectionEditor : CollectionEditor
{
public StringCollectionEditor(Type type)
: base(type)
{
}
/// <include file="doc\StringCollectionEditor.uex" path="docs/doc[@for="StringCollectionEditor.CreateCollectionForm"]/*">
/// <devdoc>
/// Creates a new form to show the current collection. You may inherit
/// from CollectionForm to provide your own form.
/// </devdoc>
protected override CollectionForm CreateCollectionForm()
{
return new StringCollectionForm(this);
}
/// <include file="doc\StringCollectionEditor.uex" path="docs/doc[@for="StringCollectionEditor.HelpTopic"]/*">
/// <devdoc>
/// <para>Gets the help topic to display for the dialog help button or pressing F1. Override to
/// display a different help topic.</para>
/// </devdoc>
protected override string HelpTopic
{
get
{
return "net.ComponentModel.StringCollectionEditor";
}
}
/// <include file="doc\StringCollectionEditor.uex" path="docs/doc[@for="StringCollectionEditor.StringCollectionForm"]/*">
/// <devdoc>
/// StringCollectionForm allows visible editing of a string array. Each line in
/// the edit box is an array entry.
/// </devdoc>
protected class StringCollectionForm : CollectionForm
{
private Label instruction;
private TextBox textEntry;
private Button okButton;
private Button cancelButton;
private TableLayoutPanel okCancelTableLayoutPanel;
private StringCollectionEditor editor = null;
/// <include file="doc\StringCollectionEditor.uex" path="docs/doc[@for="StringCollectionEditor.StringCollectionForm.StringCollectionForm"]/*">
/// <devdoc>
/// Constructs a StringCollectionForm.
/// </devdoc>
public StringCollectionForm(CollectionEditor editor)
: base(editor)
{
this.editor = (StringCollectionEditor)editor;
InitializeComponent();
HookEvents();
}
private void Edit1_keyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Escape)
{
cancelButton.PerformClick();
e.Handled = true;
}
}
private void StringCollectionEditor_HelpButtonClicked(object sender, CancelEventArgs e)
{
e.Cancel = true;
editor.ShowHelp();
}
private void Form_HelpRequested(object sender, HelpEventArgs e)
{
editor.ShowHelp();
}
private void HookEvents()
{
this.textEntry.KeyDown += new KeyEventHandler(this.Edit1_keyDown);
this.okButton.Click += new EventHandler(this.OKButton_click);
this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.StringCollectionEditor_HelpButtonClicked);
}
/// <include file="doc\StringCollectionEditor.uex" path="docs/doc[@for="StringCollectionEditor.StringCollectionForm.InitializeComponent"]/*">
/// <devdoc>
/// NOTE: The following code is required by the form
/// designer. It can be modified using the form editor. Do not
/// modify it using the code editor.
/// </devdoc>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(StringCollectionEditor));
this.instruction = new System.Windows.Forms.Label();
this.textEntry = new System.Windows.Forms.TextBox();
this.okButton = new System.Windows.Forms.Button();
this.cancelButton = new System.Windows.Forms.Button();
this.okCancelTableLayoutPanel = new System.Windows.Forms.TableLayoutPanel();
this.okCancelTableLayoutPanel.SuspendLayout();
this.SuspendLayout();
//
// instruction
//
//resources.ApplyResources(this.instruction, "instruction");
this.instruction.Margin = new System.Windows.Forms.Padding(3, 1, 3, 0);
this.instruction.Name = "instruction";
//
// textEntry
//
this.textEntry.AcceptsTab = true;
this.textEntry.AcceptsReturn = true;
//resources.ApplyResources(this.textEntry, "textEntry");
this.textEntry.Name = "textEntry";
//
// okButton
//
//resources.ApplyResources(this.okButton, "okButton");
this.okButton.DialogResult = System.Windows.Forms.DialogResult.OK;
this.okButton.Margin = new System.Windows.Forms.Padding(0, 0, 3, 0);
this.okButton.Name = "okButton";
//
// cancelButton
//
//resources.ApplyResources(this.cancelButton, "cancelButton");
this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.cancelButton.Margin = new System.Windows.Forms.Padding(3, 0, 0, 0);
this.cancelButton.Name = "cancelButton";
//
// okCancelTableLayoutPanel
//
//resources.ApplyResources(this.okCancelTableLayoutPanel, "okCancelTableLayoutPanel");
this.okCancelTableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.okCancelTableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.okCancelTableLayoutPanel.Controls.Add(this.okButton, 0, 0);
this.okCancelTableLayoutPanel.Controls.Add(this.cancelButton, 1, 0);
this.okCancelTableLayoutPanel.Name = "okCancelTableLayoutPanel";
this.okCancelTableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle());
//
// StringCollectionEditor
//
//resources.ApplyResources(this, "$this");
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.okCancelTableLayoutPanel);
this.Controls.Add(this.instruction);
this.Controls.Add(this.textEntry);
this.HelpButton = true;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "StringCollectionEditor";
this.ShowIcon = false;
this.ShowInTaskbar = false;
this.okCancelTableLayoutPanel.ResumeLayout(false);
this.okCancelTableLayoutPanel.PerformLayout();
this.HelpRequested += new HelpEventHandler(this.Form_HelpRequested);
this.ResumeLayout(false);
this.PerformLayout();
}
/// <include file="doc\StringCollectionEditor.uex" path="docs/doc[@for="StringCollectionEditor.StringCollectionForm.OKButton_click"]/*">
/// <devdoc>
/// Commits the changes to the editor.
/// </devdoc>
private void OKButton_click(object sender, EventArgs e)
{
char[] delims = new char[] { '\n' };
char[] trims = new char[] { '\r' };
string[] strings = textEntry.Text.Split(delims);
object[] curItems = Items;
int nItems = strings.Length;
for (int i = 0; i < nItems; i++)
{
strings[i] = strings[i].Trim(trims);
}
bool dirty = true;
if (nItems == curItems.Length)
{
int i;
for (i = 0; i < nItems; ++i)
{
if (!strings[i].Equals((string)curItems[i]))
{
break;
}
}
if (i == nItems)
dirty = false;
}
if (!dirty)
{
DialogResult = DialogResult.Cancel;
return;
}
// ASURT #57372
// If the final line is blank, we don't want to create an item from it
//
if (strings.Length > 0 && strings[strings.Length - 1].Length == 0)
{
nItems--;
}
object[] values = new object[nItems];
for (int i = 0; i < nItems; i++)
{
values[i] = strings[i];
}
Items = values;
}
// <summary>
// 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.
// </summary>
//
protected override void OnEditValueChanged()
{
object[] items = Items;
string text = string.Empty;
for (int i = 0; i < items.Length; i++)
{
if (items[i] is string)
{
text += (string)items[i];
if (i != items.Length - 1)
{
text += "\r\n";
}
}
}
textEntry.Text = text;
}
}
}
}
dr4g0n76
Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.
Wie meinst du das mit beim Click ausführen?
Ich hab mal ein propertyGrid mittels C1FlexGrid selbst gebastelt, und dafür folgende Klassen angelegt:
Basisklasse für TypceConverter und UITypeEditor Handling
/// <summary>
/// Basisklasse für <see cref="PropertiesControlTypeConverter"/> und <see cref="PropertiesControlUITypeEditor"/>
/// </summary>
internal class PropertiesControlTypeDescriptorContext : ITypeDescriptorContext, IServiceProvider, IDisposable
{
protected PropertiesControlTypeDescriptorContext(object instance)
{
this.instance = instance;
this.propertyDescriptors = new Dictionary<string, PropertyDescriptor>();
foreach (PropertyDescriptor pd in TypeDescriptor.GetProperties(instance))
propertyDescriptors.Add(pd.Name, pd);
}
/// <summary>
/// wechselt akt. zu bearbeitende Eigenschaft
/// </summary>
/// <param name="propertyName">name der Eigenschaft die jetzt bearbeitet werden soll</param>
internal void SetCurrentProperty(string propertyName)
{
propertyDescriptors.TryGetValue(propertyName, out propertyDescriptor);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
propertyDescriptors.Clear();
propertyDescriptor = null;
GC.SuppressFinalize(this);
}
}
#region IDisposable Members
/// <summary>
/// Ressourcen freigeben
/// </summary>
public void Dispose()
{
Dispose(true);
}
#endregion
#region Statische Methoden
/// <summary>
/// liefert <see cref="PropertyDescriptor"/> für angegebene Eigenschaft
/// </summary>
/// <param name="instance">Instance aus der Eigenschaft kommt</param>
/// <param name="propertyName">name der Eigenschaft für das <see cref="PropertyDescriptor"/> geliefert werden soll</param>
/// <returns><see cref="PropertyDescriptor"/> wenn gefunden, sonst null</returns>
protected static PropertyDescriptor GetPropertyDescriptor(object instance, string propertyName)
{
PropertyDescriptorCollection pdc = TypeDescriptor.GetProperties(instance);
foreach (PropertyDescriptor pd in pdc)
{
if (string.Equals(propertyName, pd.Name, StringComparison.OrdinalIgnoreCase))
return pd;
}
return null;
}
#endregion
#region ITypeDescriptorContext Members
/// <summary>
/// Gets the container representing this System.ComponentModel.TypeDescriptor { get; }
/// </summary>
public IContainer Container
{
get { return null; }
}
/// <summary>
/// Gets the object that is connected with this type descriptor request { get; }
/// </summary>
public object Instance
{
get { return instance; }
}
/// <summary>
/// Not Implemented
/// </summary>
public void OnComponentChanged()
{
throw new NotImplementedException("The method or operation is not implemented.");
}
/// <summary>
/// Not Implemented
/// </summary>
/// <returns></returns>
public bool OnComponentChanging()
{
throw new NotImplementedException("The method or operation is not implemented.");
}
/// <summary>
/// Gets the System.ComponentModel.PropertyDescriptor that is associated with the given context item. { get; }
/// </summary>
public PropertyDescriptor PropertyDescriptor
{
get { return propertyDescriptor; }
}
#endregion
#region IServiceProvider Members
/// <summary>
/// Gets the service object of the specified type.
/// </summary>
/// <param name="serviceType">An object that specifies the type of service object to get.</param>
/// <returns>A service object of type serviceType.-or- null if there is no service object of type serviceType.</returns>
public virtual object GetService(Type serviceType)
{
if (serviceType == this.GetType())
return this;
return null;
}
#endregion
private readonly object instance;
private readonly Dictionary<string, PropertyDescriptor> propertyDescriptors;
private PropertyDescriptor propertyDescriptor;
}
Für UITypeEditor dann:
internal class PropertiesControlUITypeEditor : PropertiesControlTypeDescriptorContext
{
public PropertiesControlUITypeEditor(Control parent, object instance)
: base(instance)
{
this.uiTypeEditors = new Dictionary<string, UITypeEditor>();
this.parent = parent;
}
/// <summary>
/// liefert akt. <see cref="UITypeEditor"/>
/// </summary>
/// <returns></returns>
private UITypeEditor GetEditor()
{
UITypeEditor uite;
if (!uiTypeEditors.TryGetValue(PropertyDescriptor.Name, out uite))
{
uite = GetEditor(Instance, PropertyDescriptor);
uiTypeEditors.Add(PropertyDescriptor.Name, uite);
}
return uite;
}
/// <summary>
/// prüft ob akt. Eigenschaft (Eigenschaft wird gesetzt über <see cref="PropertiesControlTypeDescriptorContext.SetCurrentProperty"/>) <see cref="UITypeEditor"/> gesetzt hat oder dessen Type
/// </summary>
/// <param name="instance">Instance aus der Eigenschaft stammt</param>
/// <param name="propertyName">name der zu prüfenden Eigenschaft</param>
/// <returns>true - <see cref="UITypeEditor"/> ist gesetzt</returns>
public bool HasEditor()
{
return (GetEditor() != null);
}
/// <summary>
/// ruft Editor auf und liefert Wert für akt. Eigenschaft (Eigenschaft wird gesetzt über <see cref="PropertiesControlTypeDescriptorContext.SetCurrentProperty"/>)
/// </summary>
/// <returns>neue Eigenschaftenwert</returns>
public object EditValue()
{
return GetEditor().EditValue(this, this, PropertyDescriptor.GetValue(Instance));
}
public override object GetService(Type serviceType)
{
object o = base.GetService(serviceType);
if (o == null)
{
if (serviceType == typeof(System.Windows.Forms.Design.IWindowsFormsEditorService))
{
if (windowsFormsEditorService == null)
windowsFormsEditorService = new WindowsFormsEditorService(parent);
return windowsFormsEditorService;
}
}
return null;
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (windowsFormsEditorService != null)
{
windowsFormsEditorService.Dispose();
windowsFormsEditorService = null;
}
uiTypeEditors.Clear();
}
base.Dispose(disposing);
}
#region Statische Methoden
/// <summary>
/// liefert <see cref="UITypeEditor"/> wenn gesetzt oder der Type der Eigenschaft dies gesetzt hat sonst null
/// </summary>
private static UITypeEditor GetEditor(object instance, PropertyDescriptor propertyDescriptor)
{
//EditorAttribute ea = null;
//foreach (Attribute attr in propertyDescriptor.Attributes)
//{
// if (attr is EditorAttribute)
// {
// ea = (EditorAttribute)attr;
// break;
// }
//}
//if (ea == null)
//{
// object[] attrs = propertyDescriptor.PropertyType.GetCustomAttributes(typeof(EditorAttribute), true);
// if (attrs.GetLength(0) > 0)
// ea = (EditorAttribute)attrs[0];
//}
//if (ea != null)
// return (UITypeEditor)Activator.CreateInstance(Type.GetType(ea.EditorTypeName));
//return TypeDescriptor.GetEditor(propertyDescriptor.PropertyType, typeof(UITypeEditor)) as UITypeEditor;
return propertyDescriptor.GetEditor(typeof(UITypeEditor)) as UITypeEditor;
}
/// <summary>
/// prüft ob angegebene Eigenschaft <see cref="TypeConverterAttribute"/> gesetzt hat oder dessen Type
/// </summary>
/// <param name="instance">Instance aus der Eigenschaft stammt</param>
/// <param name="propertyName">name der zu prüfenden Eigenschaft</param>
/// <returns>true - <see cref="TypeConverterAttribute"/> ist gesetzt</returns>
public static bool HasEditor(object instance, string propertyName)
{
return (GetEditor(instance, GetPropertyDescriptor(instance, propertyName)) != null);
}
#endregion
/// <summary>
/// <see cref="IWindowsFormsEditorService"/> Klasse zum behandeln des <see cref="UITypeEditor"/>
/// </summary>
private class WindowsFormsEditorService : System.Windows.Forms.Design.IWindowsFormsEditorService, IDisposable
{
internal WindowsFormsEditorService(Control parent)
{
this.parent = parent;
}
#region IWindowsFormsEditorService Members
public void CloseDropDown()
{
if (dropDownControl != null)
{
dropDownControl.Leave -= new EventHandler(control_Leave);
parent.Controls.Remove(dropDownControl);
dropDownControl = null;
}
}
public void DropDownControl(System.Windows.Forms.Control control)
{
CloseDropDown();
dropDownControl = control;
parent.Controls.Add(control);
control.BringToFront();
control.Location = parent.PointToClient(Control.MousePosition);
System.Drawing.Rectangle recParent = new System.Drawing.Rectangle(parent.Location, parent.Size);
System.Drawing.Rectangle recControl = new System.Drawing.Rectangle(control.Location, control.Size);
while (recParent.Bottom<recControl.Bottom)
recControl.Y--;
while (recParent.Right < recControl.Right)
recControl.X--;
control.Location = recControl.Location;
control.Focus();
control.Leave += new EventHandler(control_Leave);
while (true) //Schleife damit Control nicht sofort wieder verschwindet
{
Application.DoEvents();
if (dropDownControl == null)
break;
}
}
void control_Leave(object sender, EventArgs e)
{
CloseDropDown();
}
public System.Windows.Forms.DialogResult ShowDialog(System.Windows.Forms.Form dialog)
{
return dialog.ShowDialog();
}
#endregion
#region IDisposable Members
public void Dispose()
{
CloseDropDown();
}
#endregion
private readonly Control parent;
private Control dropDownControl;
}
private readonly Control parent;
private readonly Dictionary<string, UITypeEditor> uiTypeEditors;
private WindowsFormsEditorService windowsFormsEditorService;
}
Für TypeConverter:
/// <summary>
/// behandelt die TypeConverter der generierten Eigenschaften für das <see cref="PropertiesControl"/>
/// </summary>
internal class PropertiesControlTypeConverter : PropertiesControlTypeDescriptorContext
{
internal PropertiesControlTypeConverter(object instance)
: base(instance)
{
this.typeConverters = new Dictionary<string, TypeConverter>();
}
/// <summary>
/// liefert <see cref="TypeConverter"/> für akt. Eigenschaft (Eigenschaft wird gesetzt über <see cref="PropertiesControlTypeDescriptorContext.SetCurrentProperty"/>)
/// </summary>
private TypeConverter GetConverter()
{
TypeConverter tc;
if (!typeConverters.TryGetValue(PropertyDescriptor.Name, out tc))
{
tc = GetConverter(Instance, PropertyDescriptor);
typeConverters.Add(PropertyDescriptor.Name, tc);
}
return tc;
}
/// <summary>
/// prüft ob akt. Eigenschaft (Eigenschaft wird gesetzt über <see cref="PropertiesControlTypeDescriptorContext.SetCurrentProperty"/>) <see cref="TypeConverter"/> gesetzt hat oder dessen Type
/// </summary>
/// <returns>true - <see cref="TypeConverter"/> ist gesetzt</returns>
public bool HasConverter()
{
return (GetConverter() != null);
}
/// <summary>
/// liefert Wert wie er angezeigt werden muss für akt. Eigenschaft (Eigenschaft wird gesetzt über <see cref="PropertiesControlTypeDescriptorContext.SetCurrentProperty"/>)
/// </summary>
/// <param name="value">akt. Wert aus Eigenschaft</param>
/// <returns>Wert für Anzeige</returns>
public virtual string GetPropertyTextValue(object value)
{
string str = null;
try
{
str = GetConverter().ConvertToString(this, value);
}
catch (Exception)
{
//Exception durchfallen lassen kommt von Microsoft (aus: System.Windows.Forms.PropertyGridInternal.GridEntry.GetPropertyTextValue)
}
if (str == null)
{
str = string.Empty;
}
return str;
}
/// <summary>
/// liefert Wert wie er in die Eigenschaft zurück geschrieben werden muss für akt. Eigenschaft (Eigenschaft wird gesetzt über <see cref="PropertiesControlTypeDescriptorContext.SetCurrentProperty"/>)
/// </summary>
/// <param name="str">akt. Wert laut Anzeige</param>
/// <returns>Wert für Eigenschaft</returns>
public virtual object SetPropertyTextValue(string str)
{
TypeConverter tc = GetConverter();
if (tc.CanConvertFrom(this, typeof(string)))
{
return tc.ConvertFromString(this, str);
}
return str;
}
/// <summary>
/// Returns whether this object supports a standard set of values that can be picked from a list, using the specified context.
/// </summary>
/// <returns>true if System.ComponentModel.TypeConverter.GetStandardValues() should be called to find a common set of values the object supports; otherwise, false.</returns>
public bool GetStandardValuesSupported()
{
return GetConverter().GetStandardValuesSupported(this);
}
/// <summary>
/// Returns a collection of standard values for the data type this type converter is designed for when provided with a format context.
/// </summary>
/// <returns>A ICollection that holds a standard set of valid values, or null if the data type does not support a standard set of values.</returns>
public ICollection GetStandardValues()
{
return GetConverter().GetStandardValues(this);
}
protected override void Dispose(bool disposing)
{
if (disposing)
typeConverters.Clear();
base.Dispose(disposing);
}
#region Statische Methoden
/// <summary>
/// liefert eine <see cref="TypeConverterAttribute"/> wenn gesetzt oder der Type der Eigenschaft dies gesetzt hat sonst null
/// </summary>
private static TypeConverter GetConverter(object instance, PropertyDescriptor propertyDescriptor)
{
//TypeConverterAttribute tca = null;
//foreach (Attribute attr in propertyDescriptor.Attributes)
//{
// if (attr is TypeConverterAttribute)
// {
// tca = (TypeConverterAttribute)attr;
// break;
// }
//}
//if (tca == null)
//{
// object[] attrs = propertyDescriptor.PropertyType.GetCustomAttributes(typeof(TypeConverterAttribute), true);
// if (attrs.GetLength(0) > 0)
// tca = (TypeConverterAttribute)attrs[0];
//}
//if (tca != null)
//{
// try
// {
// return (TypeConverter)Activator.CreateInstance(Type.GetType(tca.ConverterTypeName));
// }
// catch (MissingMethodException) //wenn kein Parameterloser Konstruktor (nur Parameter Type erlaubt)
// {
// return (TypeConverter)Activator.CreateInstance(Type.GetType(tca.ConverterTypeName), propertyDescriptor.PropertyType);
// }
//}
//return null;
return propertyDescriptor.Converter;
}
/// <summary>
/// prüft ob angegebene Eigenschaft <see cref="TypeConverterAttribute"/> gesetzt hat oder dessen Type
/// </summary>
/// <param name="instance">Instance aus der Eigenschaft stammt</param>
/// <param name="propertyName">name der zu prüfenden Eigenschaft</param>
/// <returns>true - <see cref="TypeConverterAttribute"/> ist gesetzt</returns>
public static bool HasConverter(object instance, string propertyName)
{
return (GetConverter(instance, GetPropertyDescriptor(instance, propertyName)) != null);
}
#endregion
private readonly Dictionary<string, TypeConverter> typeConverters;
}
Im Prinzip dann nur SetCurrentProperty aufrufen mit HasEditor prüfen ob Editor angegeben wurde und mit EditValue kommt dann der Editor