Author Topic: Newby: WPF form combobox populated with Dictionary<string, SmallLayerObject>  (Read 223 times)

0 Members and 1 Guest are viewing this topic.

ingenieur3d

  • Mosquito
  • Posts: 9
I come from VBA and I am programming above my capacities, but without frustration. I'm stuck, so I seek help.

I have this WPF form that has a combobox populated with the layer names. In my design the selection of a layer is optional, for that reason item[0] is a message "<Do not filter on layer>". Then from item 1 onwards the combobox is populated with the layernames.

After some thinking I made a peculiar choice and started implementing a Dictionary<string, SmallLayerObject> variable. That seems complex to me, but worth the try, for it seemed strong and flexible. I read from the LayerTable into a SortedList<string, SmallLayerObject>. That code looks like this:


Code - C#: [Select]
  1.     Transaction trans = DrawingDatabase.TransactionManager.StartTransaction();
  2.  
  3.     SortedList<string, SmallLayerObj> LayersSorted = new SortedList<string, SmallLayerObj>();
  4.  
  5.     LayerTable lyrTbl = trans.GetObject(DrawingDatabase.LayerTableId, OpenMode.ForRead) as LayerTable;
  6.  
  7.     foreach (ObjectId lyrId in lyrTbl)
  8.     {
  9.         lyrTblRec = trans.GetObject(lyrId, OpenMode.ForRead) as LayerTableRecord;
  10.  
  11.         lyrObj = new SmallLayerObj
  12.         {
  13.             BaseId = lyrId,
  14.             IsFrozen = lyrTblRec.IsFrozen,
  15.             Name = lyrTblRec.Name
  16.         };
  17.         LayersSorted.Add(lyrTblRec.Name, lyrObj);
  18.     }
  19.  
  20.     Dictionary<string, SmallLayerObj> LayerDict = new Dictionary<string, SmallLayerObj>
  21.     {
  22.         // the defMessage is a string "<Do not filter on layer>"
  23.         { defMessage, new SmallLayerObj { Name = null, BaseId = ObjectId.Null, IsFrozen = false } }
  24.     };
  25.  
  26.     foreach (KeyValuePair<string, SmallLayerObj> layerName in LayersSorted)
  27.     {
  28.         LayerDict.Add(layerName.Key, layerName.Value);
  29.     }
  30.  
  31.     return LayerDict;
  32.  


It still needs attention, but it works. In the long run it will allow me to expand the SmallLayerObj without much effort.

Now my data is bound with this XAML syntax: ItemsSource="{Binding}" DisplayMemberPath="Key" SelectedValuePath="Value.BaseId". I am not sure if the SelectedValuePath="Value.BaseId" is working and what it is supposed to do, but the DisplayMemberPath="Key" is working and the combobox is populated with the layernames.

Now I have this return value

Code - C#: [Select]
  1.     var lyr = win.cboLayers.SelectedItem;
  2.  

and the lyr variable is actually a Generic.KeyValuePair

My problem is that I have no clue how to read out the ObjectId that is stored in the Value part that is a SmallLayerObj with three items. .TryGetValue? using an indexer? I have no clue and even the IntelliSense does not offer help. It is beyond my reach...


gile

  • Water Moccasin
  • Posts: 2275
  • Marseille, France
Hi,
It looks like you make things more complex than they are.

First, you do not need to build a SortedList:
Code - C#: [Select]
  1.     Transaction trans = DrawingDatabase.TransactionManager.StartTransaction();
  2.  
  3.     Dictionary<string, SmallLayerObj> LayerDict = new Dictionary<string, SmallLayerObj>
  4.     {
  5.         // the defMessage is a string "<Do not filter on layer>"
  6.         { defMessage, new SmallLayerObj { Name = null, BaseId = ObjectId.Null, IsFrozen = false } }
  7.     };
  8.  
  9.     LayerTable lyrTbl = trans.GetObject(DrawingDatabase.LayerTableId, OpenMode.ForRead) as LayerTable;
  10.  
  11.     foreach (ObjectId lyrId in lyrTbl)
  12.     {
  13.         lyrTblRec = trans.GetObject(lyrId, OpenMode.ForRead) as LayerTableRecord;
  14.  
  15.         lyrObj = new SmallLayerObj
  16.         {
  17.             BaseId = lyrId,
  18.             IsFrozen = lyrTblRec.IsFrozen,
  19.             Name = lyrTblRec.Name
  20.         };
  21.         LayerDict.Add(lyrTblRec.Name, lyrObj);
  22.     }
  23.  
  24.     return LayerDict;

But it seems to me, you do not need to use a Dictionary:
Code - C#: [Select]
  1.     Transaction trans = DrawingDatabase.TransactionManager.StartTransaction();
  2.  
  3.     List<SmallLayerObj> LayerList = new List<SmallLayerObj>
  4.     {
  5.         // the defMessage is a string "<Do not filter on layer>"
  6.         new SmallLayerObj { Name = null, BaseId = ObjectId.Null, IsFrozen = false }
  7.     };
  8.  
  9.     LayerTable lyrTbl = trans.GetObject(DrawingDatabase.LayerTableId, OpenMode.ForRead) as LayerTable;
  10.  
  11.     foreach (ObjectId lyrId in lyrTbl)
  12.     {
  13.         lyrTblRec = trans.GetObject(lyrId, OpenMode.ForRead) as LayerTableRecord;
  14.  
  15.         lyrObj = new SmallLayerObj
  16.         {
  17.             BaseId = lyrId,
  18.             IsFrozen = lyrTblRec.IsFrozen,
  19.             Name = lyrTblRec.Name
  20.         };
  21.         LayerList.Add(lyrObj);
  22.     }
  23.  
  24.     return LayerList;
and in the XAML:
Code - XML: [Select]
  1. ItemsSource="{Binding}" DisplayMemberPath="Name" SelectedValuePath="BaseId"

To reply to your request, in the first case (Dictionary):
Code - C#: [Select]
  1. var lyrId = win.cboLayers.SelectedItem.Value.BaseId;
in the second case (List)
Code - C#: [Select]
  1. var lyrId = win.cboLayers.SelectedItem.BaseId;
Speaking English as a French Frog

ingenieur3d

  • Mosquito
  • Posts: 9
Hi Gile,

I'll give you a big thanks after I've implemented your simplification. First, my first question.

Here the
Code - C#: [Select]
  1.     var lyrId = win.cboLayers.SelectedItem.Value.BaseId;
  2.  
does not work. It says 'object' does not contain a definition for 'value'.
Might it be that I made it so complex that I obscured the Value property?

I figured that I need to cast as a KeyValuePair<string, SmallLayerObj> to gain access.

Code - C#: [Select]
  1.     var VarSelLyr = win.cboOutputL.SelectedItem;
  2.  
  3.     Dictionary<string, SmallLayerObj> DictLyr = null;
  4.     KeyValuePair<string, SmallLayerObj> KVPLyr;
  5.     SmallLayerObj LyrObj = null;
  6.  
  7.     if (VarSelLyr is Dictionary<string, SmallLayerObj> == true)
  8.     {
  9.         DictLyr = (Dictionary<string, SmallLayerObj>)VarSelLyr;
  10.         // The next one fails: IntelliSense writes
  11.         // Dictionary<string, SmallLayerObj> does not contain a definition for 'value'.
  12.         if (DictLyr.Value is SmallLayerObj == true)
  13.             LyrObj = (SmallLayerObj)KVPLyr.Value;
  14.         }
  15.  
  16.     if (VarSelLyr is KeyValuePair<string, SmallLayerObj> == true)
  17.     {
  18.         KVPLyr = (KeyValuePair<string, SmallLayerObj>)VarSelLyr;
  19.         // This works
  20.         if (KVPLyr.Value is SmallLayerObj == true)
  21.             LyrObj = (SmallLayerObj)KVPLyr.Value;
  22.     }
  23.  
  24.     acDoc.Editor.WriteMessage("Name value = " + LyrObj.Name.ToString());
  25.  

Strange! But you offered me a better solution. Thanks!!

ingenieur3d

  • Mosquito
  • Posts: 9
This way the list of layers is unsorted. How so you solve that?

PS: And I agree, no need for the message.  :-D

gile

  • Water Moccasin
  • Posts: 2275
  • Marseille, France
Try this:
Code - C#: [Select]
  1. var lyrId = ((KeyValuePair<string, SmallLayerObj>)win.cboLayers.SelectedItem).Value.BaseId;
Speaking English as a French Frog

ingenieur3d

  • Mosquito
  • Posts: 9
Hi!

@gile. Thanks! In the mean time I've implemented your code, without the SortedList, without the Dictionary.

Now my combobox listing isn't sorted. I have Troelsen's "Pro C# 6.0..." here on the desk, but way to little experience to solve the sorting of the Name property. Any guidance is really appreciated.

Should I implement the IComparer or the IComparer<T> interface (and then which one)? And write a custom compare routine on the LayerDic.Name? Or would a Linq expression be able to do the sorting?

Hope nobody is bothered with me asking this. I believe I'm capable to find it out, but some direction, in the best instance with some sample code, would be really welcome.

gile

  • Water Moccasin
  • Posts: 2275
  • Marseille, France
IEnumerable<T> extension methods is your friend.
Code - C#: [Select]
  1. using system.Linq;
  2. ...
  3. LayerList = LayerList.OrderBy(l => l.Name);
Speaking English as a French Frog

ingenieur3d

  • Mosquito
  • Posts: 9
Thanks for your help!

Quote
IEnumerable<T> extension methods is your friend.

And that is going to be a complex friendship.  8-)