Custom Collection Editor - how to block the up and down buttons ?

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

I have a Custom Collection Editor and overridden some methods - everything
works fine...

BUT I now want to block the up and down buttons, so the User won't be able
to move the Collection Items within the Index.

Is there any possibilty by overriding a method so it won't move the
collection items?

To make it clear - I do not want to remove the buttons or make them
invisible, I just want to block the functionality.

Thank you in advance,
Robert.
 
Hi Robert,

I have spent several hours researching on this problem. Unfortunately, I
haven't found any property or overridable method in CollectionEditor class
to disable the up and down buttons in the collection editor dialog.

I have tried to override the EditValue method. In the overridden EditValue
method, the line of code 'base.EditValue(context, provider, value);'
displays the collection editor dialog. But it's hard to get the dialog. And
even if we could get the dialog, it might be impossible to disable the up
and down button in the dialog, for the dialog may not expose such a
property or method to allow us to do it.

Coud you tell me why you want to disable the up and down buttons in the
collection dialog? In my opinion, this function is very convenience for the
user.

I will go on researching on this issue and as soon as I have a new finding,
I will get it back to you.

Have a nice weekend!


Sincerely,
Linda Liu
Microsoft Online Community Support

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
 
Hi Linda!

I have one Collection, which holds 'Distances' (in meters - declared as
float), but it's vital that it has some kind of sort order.

I have already (successfully) done some tricks to keep these values in
order, even if the user adds new values via dialog 'add' button ;) ... - with
'in order' I mean the index of the Collection, i.e. index[0] 100 / index[1]
200 / index[2] 500, so if one adds a new value of 300, the collection will
look like this: index[0] 100 / index[1] 200 / index[2] 300 / index[3] 500...

If the 'add' button is pushed the newly added distance will be set to a
value of 100(m) greater than the last element in the collection shows and if
someone sets a new value the collection is resorted automatically ;) ...

This is done by some (ugly ;) ) code within the Set Accessor like this:

/// <summary>
/// lod_distance of lod_distances.
/// </summary>
[Bindable(false),
Category("Excelsior - Data"),
Description("lod_distance of lod_distances.")]
public float lod_distance
{
get { return this.m_lod_distance; }
set
{
if (value <= 0) return;
this.m_lod_distance = value;
// mighty nasty Hack, but I **REALLY** LOVE IT ;)
if
(Convert.ToBoolean(Excelsior.Win32specific.Win32Registry.ReadObjectFromRegistry(Excelsior.Win32specific.ExcelsiorProjectIdentifier.EPI_TOOLSET,
"ReorgFlag"))) return;

Excelsior.Win32specific.Win32Registry.WriteObjectToRegistry(Excelsior.Win32specific.ExcelsiorProjectIdentifier.EPI_TOOLSET, "ReorgFlag", 1);
float[] sortDistances = new
float[((Material)this.Parent).lod_distances.Count];
for (int i = 0; i <
((Material)this.Parent).lod_distances.Count; i++)
{
sortDistances =
((Material)this.Parent).lod_distances.lod_distance;
}
Array.Sort(sortDistances);
for (int i = 0; i <
((Material)this.Parent).lod_distances.Count; i++)
{
((Material)this.Parent).lod_distances.lod_distance =
sortDistances;
}

Excelsior.Win32specific.Win32Registry.WriteObjectToRegistry(Excelsior.Win32specific.ExcelsiorProjectIdentifier.EPI_TOOLSET, "ReorgFlag", 0);
}
}

This is possible because the Collection is a property of another class and
holds a refernce to the parent object - was really hard to get the Parent
object set if an item is added via Collection Editor 'add'-Button, but I got
this up and running ;) using this Code:

/// <summary>
/// override CreateInstance to implement our wanted behavior,
/// setting a Reference to the Parent (Material) object,
/// which holds the LoD_Distance Collection.
/// </summary>
protected override object CreateInstance(Type ItemType)
{
LoD_Distance lod = (LoD_Distance)base.CreateInstance(ItemType);
if (this.Context.Instance != null)
{
if (this.Context.Instance is Material)
{
lod.SetParentObject((Material)this.Context.Instance);
float[] sortDistances = new
float[((Material)this.Context.Instance).lod_distances.Count];
for (int i = 0; i <
((Material)this.Context.Instance).lod_distances.Count; i++)
{
sortDistances =
((Material)this.Context.Instance).lod_distances.lod_distance;

System.Diagnostics.Debug.WriteLine(sortDistances.ToString());
}
Array.Sort(sortDistances);
if (sortDistances.Length >= 1)
lod.lod_distance =
sortDistances[sortDistances.Length - 1] + 100;
else
lod.lod_distance = 100;
}
}
return lod;
}

So everythings work fine, until the User moves the Collection Items via the
up/down Buttons, so I just want to get notified if this 'event' happens, so I
can resort my Collection again, as I did in the Code above.

Actually it is not necessary to 'block' the buttons, I am searching for a
way to get notified that one of the buttons has been pushed, so I can re-sort
my Collection Items to get this undone...

Thank you for your help!

Robert
 
Hi Robert,

Thank you for your detailed explaination. I understand why you want to
block the up and down buttons in the collection editor dialog now.

To get notified when one of the up and down buttons is pushed, we would
have two possible ways. One is to handle some event of the collection
editor dialog and the other is to handle some event of the collection.

As for the first 'option', we couldn't even get the collection editor
dialog. Say nothing of handling some event of the editor dialog. As for the
second 'option', I don't know which type the collection is in your project.
The type of the collection in my test project is List<T>, which hasn't even
one event.

So it seems that the two possible candidates aren't feasible.

In fact, since CollectionEditor is inherited from UITypeEditor and
implement the EditValue method to popup the collection editor dialog and
return the collection, we could override the EditValue method and re-sort
the collection after the collection editor dialog is closed.

The following is a sample of overriding the EditValue method.

public class MyCollectionEditor:CollectionEditor
{
public MyCollectionEditor(Type type):base(type)
{
}
public override object EditValue(ITypeDescriptorContext context,
IServiceProvider provider, object value)
{
object ins = base.EditValue(context, provider, value);
if (context.Instance != null)
{
if (context.Instance is Material)
{
// add your code to re-sort the collection in the
Material object, e.g ((Material)context.Instance).SortList();

}
}
return ins;
}
}

Since we need to re-sort the collection out of the LoD_Distance class, I
recommend you to add a method in the Material class to re-sort the
collection in it. And make some small modifications in the LoD_Distance
class. The following is a sample.

using System.Collections.Generic;
using System.Drawing.Design;
using System.ComponentModel;

class Material
{
private List<LoD_Distance> lists = new List<LoD_Distance>();
[Editor(typeof(MyCollectionEditor),typeof(UITypeEditor))]
public List<LoD_Distance> lod_distances
{
get { return lists; }
}
public Material()
{

}
public void SortList()
{
float[] sortDistances = new float[this.lod_distances.Count];
for (int i = 0; i < this.lod_distances.Count; i++)
{
sortDistances = this.lod_distances.lod_distance;
}

Array.Sort(sortDistances);
for (int i = 0; i < this.lod_distances.Count; i++)
{
this.lod_distances.needsorting = false;
this.lod_distances.lod_distance = sortDistances;
this.lod_distances.needsorting = true;
}
}
}

class LoD_Distance
{
public bool needsorting = true;

[Bindable(false),Category("Excelsior -
Data"),Description("lod_distance of lod_distances.")]
public float lod_distance
{
get { return this.m_lod_distance; }
set
{
if (value <= 0) return;
this.m_lod_distance = value;

if (needsorting == true)
{
this.parent.SortList();
}

}
}

private float m_lod_distance=0;
private Material parent = null;
public Material Parent
{
get { return parent; }
}
public void SetParentObject(Material obj)
{
parent = obj;
}
}

Hope this helps.
If you have anything unclear, please feel free to let me know.


Sincerely,
Linda Liu
Microsoft Online Community Support
 
Hi Linda and Robert,

1. About second option Linda mentioned,
maybe one could use System.Collections.CollectionBase as
base class for collection in question.
This class provides protected virtual events like OnInsert, OnRemove,
OnClear.

2) According to
http://www.codeproject.com/csharp/DzCollectionEditor.asp
CollectionEditor works with IList, so one could implement a class that
implements IList and trace how CollectionEditor move items up or down.
By knowing this implementation can be changed to prevent moving of items
up or down.


Hope it helps.

Petar Repac
 
Hi Linda, hi Peter!

First I want to thank Linda for her information, helped me a lot...

I think overriding the EditValue Method will be my favorite solution - it's
really ok
to start sorting on closing the Editor...
1. About second option Linda mentioned,
maybe one could use System.Collections.CollectionBase as
base class for collection in question.
This class provides protected virtual events like OnInsert, OnRemove,
OnClear.

I am already deriving my Collection from CollectionBase, nice to know that
there are events which can be used - I 'll look into this soon... - thank
you, Peter!
2) According to
http://www.codeproject.com/csharp/DzCollectionEditor.asp
CollectionEditor works with IList, so one could implement a class that
implements IList and trace how CollectionEditor move items up or down.
By knowing this implementation can be changed to prevent moving of items
up or down.

Sounds not easy - I have already looked at Collection Editor's code, but
it's not easy to understand - I must admit that I would have coded Collection
Editor much simpler than MS did ;) - but I am far away from writing such
complex things like .NET Framework - so I think your second suggestion is too
time consuming to implement - at least for me ;) !

Thank you Linda, thank you Peter!

Robert
 
Back
Top