The order of the items in the dictionary are unimportant provided it doesn't change immediately after its creation. In fact, in practice, the order of layouts returned by the third party tool seldom match the actual order of the layouts in the drawing except that item[0] is always "Model". Its merely a selection tool to pair up the layout handle with the layout name.
The project called for storing xRecord data uniquely identifiable per layout but not attached to the layout so it will always be available even if the layout is subsequently deleted.
In comes the entity handle ... each layout has one that is unique and is mostly stable .. unless the user wblocks the drawing or does a couple of other things that aren't typically done on a regular basis.
The program captures the entity handle (key) and name (value) of each layout and populates a combobox with that information.
The form can be instantiated with no specific layout as the selected item in which case it always defaults to "Model" or the user can open the form and pass a layout name (because that's the only way a user can identify a layout) … this is where the issue comes in.
The combobox datasource is a dictionary <string, string> where the key is the layout handle and the value is the layout name. It is created on the fly every time the form is shown and is never modified. When the user passes a layout name, during initialization, the SelectedIndex of the combobox needs to be set so that the correct information can be populated in the remaining controls. Now, the user has no way of knowing that the data is keyed under H3A or B94 or whatever the handle happens to be, but they do know that the layout is called "Model" or "Populated evidence v2 2021" or whatever the case may be.
Because the layout name is the Value and not the Key, nothing out of the box allows me to figure out that "Populated evidence v2 2021" is index 4 so I have to iterate over the collection and find the first instance (also layout names must be unique too so it will actually be the only one found).
When the form is disposed, the dictionary goes with it. The index is never used again except when the combobox SelectedItem is changed.
private void Form_Load()
{
_loading = true;
try
{
//external library LayoutHelper
LayoutHelper helper
= new LayoutHelper
(); string caption = helper.getDWGName(FilenameStyle.Elipsed);
Dictionary<string, string> cs = helper.getLayouts().ToDictionary();
//Bind layout info to combobox
cbxLayouts
.ComboBox.DataSource = new BindingSource
(cs,
null); cbxLayouts.ComboBox.DisplayMember = "Value";
cbxLayouts.ComboBox.ValueMember = "Key";
//_initialLayout is "Model" or a string passed in the constructor -1 returned if no matching layout found
cbxLayouts.SelectedIndex = getFirstIndexOf(_initialLayout, cs);
if (cbxLayouts.Text != "")
{
//Get the xRecords with the matching layout handle (primary) or name (secondary)
_data = helper.getXrecords(((KeyValuePair<string, string>)cbxLayouts.SelectedItem()).Key, ((KeyValuePair<string, string>)cbxLayouts.SelectedItem()).Value);
}
}
catch{}
_loading = false;
}
private void cbxLayouts_SelectedIndexChanged(object sender, EventArgs e)
{
if (!_loading)
{
try
{
_data = helper.getXrecords(((KeyValuePair<string, string>)cbxLayouts.SelectedItem()).Key, ((KeyValuePair<string, string>)cbxLayouts.SelectedItem()).Value);
}
catch{}
}
}
//Find index of a given value in a Dictionary<string, string>
//-1 if not found
public int getFirstIndexOf(string search, Dictionary<string, string> mydict)
{
int i = 0;
foreach (KeyValuePair<string, string> item in mydict)
{
if (item.Value == search)
{
return i;
}
i++;
}
return -1;
}
This itself may not be the best way to handle the task, but its what I have to work with. If I could tell the function to return the data in a different manner (say swapping Value and Key) I could make Key the DisplayMember and then get the Value member of layout handle using OOB functions.