Component Communication at Design Time
I want to have a "form" or something else (no matter what) that can add string to a List
it would be done with a First Component "StringManager
" witch contains the string collection
On the other hand i want to have another Component "ComponentReader
" that use IExtenderProvider and add on All controls (on the component form) a property named "TheString" which let me choose in one of the string from List
So, to be clear : i want to share the List<String>
with the minimum of code on each forms, (the most with properties editor)
I don't know how can i tell the "ComponentReader
" where is the main component that he refers,
(i 've add a property ReferedStringManager
in my "ComponentReader
").
Is there any properties or instruction (or way)to inspect the project and his references to get all matchable value as List in "ComponentReader
" properti开发者_StackOverflow社区es
for the ReferedStringManager
property of the ComponentReader
;
If its not possible ,i think of Static List or something else, maybe XML file, (but i don't know how to manage that during conception )
Of course all of that is at Design Time, not at Execution Time (it would be so simpler !!)
this is a late answer, but if you're still interested, here's how to do it.
There are quite a few requirements for both your StringManager and your ComponentReader classes.
1) both classes need to derive from System.ComponentModel.Component.
2) The StringManager must override the Site property of the Component class. This is what makes it "VS Designer aware", and allows it to be selectable in your ComponentReader's properties later on.
3) The StringManager must expose the List as a public property. For convenience, in my sample code bolow, I have set the EditorAttribute for easy string collection edition in the VS property grid.
4) The ComponentReader must implement a custom interface with only one property of type StringManager. This is needed by the requirement #6.
5) The ComponentReader must have a public property of type StringManager
6) The ComponentReader must have a public property of type string for the SelectedString. The catch is that we must set the TypeConverterAttribute to yet another class that we must implenent (see #7)
7) We must implement a StringConverter derived class. This will be used to allow us to select a string from the selected StringManager. Within this class, we must be able to retrieve a reference to the ComponentReader through the interface created in #4.
Now, for the code:
StringManager.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Windows.Forms;
using System.ComponentModel.Design;
namespace VSDesignHost
{
class StringManager : Component
{
private ContainerControl _containerControl = null;
public StringManager()
{
TheList = new List<string>();
}
public StringManager(IContainer container) : this()
{
container.Add(this);
InitializeComponent();
}
private void InitializeComponent()
{
//Whatever
}
public ContainerControl ContainerControl
{
get { return _containerControl; }
set { _containerControl = value; }
}
public override ISite Site
{
set
{
base.Site = value;
if (value != null)
{
IDesignerHost host = value.GetService(typeof(IDesignerHost)) as IDesignerHost;
if (host != null)
{
IComponent rootComponent = host.RootComponent;
if (rootComponent is ContainerControl)
{
this.ContainerControl = (ContainerControl)rootComponent;
}
}
}
}
}
[Editor("System.Windows.Forms.Design.StringCollectionEditor, System.Design", "System.Drawing.Design.UITypeEditor, System.Drawing")]
public List<string> TheList { get; set; }
}
}
ComponentReader.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
namespace VSDesignHost
{
class ComponentReader : Component, IStringManagerEnabled
{
private StringManager sm;
public ComponentReader()
{
sm = null;
}
[Browsable(true), Category("MyCategory")]
public StringManager StringManager
{
get { return sm; }
set
{
sm = value;
}
}
[Browsable(true), Category("MyCategory"), TypeConverter(typeof(StringManagerStringConverter))]
public string SelectedString { get; set; }
}
}
IStringManagerEnabled.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace VSDesignHost
{
interface IStringManagerEnabled
{
StringManager StringManager
{
get;
set;
}
}
}
StringManagerStringConverter.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
namespace VSDesignHost
{
class StringManagerStringConverter : StringConverter
{
#region Make It A ComboBox
public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
{
return true;
}
public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
{
return false;
}
#endregion
#region Display Tags In List
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
{
if ((context == null) || (context.Container == null))
{
return null;
}
Object[] Tags = this.GetTagsFromServer(context);
if (Tags != null)
{
return new StandardValuesCollection(Tags);
}
return null;
}
private object[] GetTagsFromServer(ITypeDescriptorContext context)
{
List<string> availableTags = new List<string>();
if (context.Instance == null)
{
availableTags.Add("ITypeDescriptorContext.Instance is null");
return availableTags.ToArray();
}
IStringManagerEnabled inst = context.Instance as IStringManagerEnabled;
if (inst == null)
{
availableTags.Add(context.Instance.ToString());
return availableTags.ToArray();
}
if (inst.StringManager == null)
{
availableTags.Add("No StringManager selected");
return availableTags.ToArray();
}
availableTags = inst.StringManager.TheList;
availableTags.Sort(Comparer<string>.Default);
return availableTags.ToArray();
}
#endregion
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
return true;
return base.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
if (value is string)
return value.ToString();
return base.ConvertFrom(context, culture, value);
}
}
}
Create a Windows Forms project, add these files to it, and build the project.
Now, on you Form, you can add an instance of each the StringManager and ComponentReader by dragging from the toolbox.
Select the StringManager, and in the properties, add a few string to TheList by using the string collection editor.
Select the ComponentReader, and in the properties windows, you should be able to select your StringManager instance from the dropdown list.
You should now be able to select one of the string from the dropdown for SelectedString.
I hope you enjoy
Luc
精彩评论