Hi,
<snip>
1) what is the best way to make it automatically update the
KeyedCollection indexing,
You have to update it yourself using the ChangeItemKey method when the Name
property changes. There are a few different ways to accomplish that. I've
posted code that uses an event, after my sig.
2) what is the best way to make the
PropertyGrid disallow existing keys from the collection
That behavior exists already in my example code below. The ChangeItemKey
method throws an ArgumentException stating, "An item with the same key has
already been added". I've caught and rethrown it with a more meaningful
message. The PropertyGrid suppresses the exception and displays a special
message box containing a predefined message with my wrapper message as
details.
3) what is
the best way to generate an instance name similar to the way the Forms
Designer generates names for instances.
Check out the MissionManager class after my sig. Specifically, the
CreateUniqueName method.
I haven't added comments because the code seems self-explanatory to me, but
if anything is unclear just let me know and I'll explain it.
--
Dave Sexton
static class MissionManager
{
public static readonly MissionCollection Missions = new
MissionCollection();
public static string CreateUniqueName()
{
string name = "Mission_";
int i = Missions.Count + 1;
while (Missions.Contains(name + i))
i++;
return name + i;
}
}
class Mission
{
public string Name
{
get
{
return name;
}
set
{
if (name == value)
return;
OnNameChanging(new NameChangingEventArgs(value));
name = value;
}
}
private string name;
public Mission(string name)
{
this.name = name;
}
private readonly object NameChangingEventLock = new object();
private EventHandler<NameChangingEventArgsNameChangingEven t;
/// <summary>
/// Event raised when the <see cref="Name" /property value is about to
be changed.
/// </summary>
public event EventHandler<NameChangingEventArgsNameChanging
{
add
{
lock (NameChangingEventLock)
{
NameChangingEvent += value;
}
}
remove
{
lock (NameChangingEventLock)
{
NameChangingEvent -= value;
}
}
}
/// <summary>
/// Raises the <see cref="NameChanging" /event.
/// </summary>
/// <param name="e"><see cref="NameChangingEventArgs" /object that
contains the new name for the property.</param>
protected virtual void OnNameChanging(NameChangingEventArgs e)
{
EventHandler<NameChangingEventArgshandler = null;
lock (NameChangingEventLock)
{
handler = NameChangingEvent;
if (handler == null)
return;
}
handler(this, e);
}
}
class NameChangingEventArgs : EventArgs
{
public string NewName { get { return newName; } }
private readonly string newName;
public NameChangingEventArgs(string newName)
{
this.newName = newName;
}
}
class MissionCollection : KeyedCollection<string, Mission>
{
protected override void InsertItem(int index, Mission item)
{
item.NameChanging += HandleNameChange;
base.InsertItem(index, item);
}
protected override void SetItem(int index, Mission item)
{
item.NameChanging += HandleNameChange;
base.SetItem(index, item);
}
protected override void RemoveItem(int index)
{
this[index].NameChanging -= HandleNameChange;
base.RemoveItem(index);
}
protected override void ClearItems()
{
foreach (Mission mission in this)
mission.NameChanging -= HandleNameChange;
base.ClearItems();
}
private void HandleNameChange(object sender, NameChangingEventArgs e)
{
try
{
base.ChangeItemKey((Mission) sender, e.NewName);
}
catch (ArgumentException ex)
{
throw new ArgumentException("The specified Name is already in use by
another Mission.", ex);
}
}
protected override string GetKeyForItem(Mission item)
{
return item.Name;
}
}