In our project (Windows app, Winforms), the UI is designed based on XML configuration file. I have a program to read the UI configuration file and Parse the configuration and design the UI.
The configuration file is designed for a complex UI. The UI has Frame
s, and Frame
s can have Tabs, Tabs->Tabs-> finally one control to display the content.
Following are two methods which are heavily used recursively. Their hit count is roughly 2000 or more times.
DeserializeChildren
DeserializeFrames
Inside these methods we have plain old nested, multiple for
loops. I try to refactor these methods but I couldn't find any alternative way to do the program other than what it is currently.
private void DeserializeChildren(WindowConfig config, string parent)
{
if (config.Frame.ChildControls == null)
{
config.Frame.ChildControls = DeserializeFrames(parent);
}
if (config.Commands == null)
{
config.Commands = DeserializeCommands(parent);
}
List<SerializerContainer> scList = list.FindAll(sc => (sc.Parent == parent) &&
(sc.Processed == false) &&
(sc.ConfigType == WINDOWCONFIG));
List<WindowConfig> wcList = new List<WindowConfig>();
scList = ListSort(scList);
foreach (SerializerContainer sc in scList)
{
string nextParent = sc.Name;
WindowConfig windowConfig; // = new WindowConfig();
windowConfig = DeserializeIt<WindowConfig>(sc.Config);
sc.Processed = true;
wcList.Add(windowConfig);
DeserializeChildren(windowConfig, parent + nextParent);
}
if (wcList.Count > 0)
{
config.ChildWindows = wcList.ToArray();
}
return;
}
The above code has a call to DeserializeFrames
, which is a recursive method.
private ControlItemConfig[] DeserializeFrames(string parent)
{
List<SerializerContainer> scList = list.FindAll(sc => (sc.Parent == parent) &&
(sc.Processed == false) &&
(sc.ConfigType == CONTROLITEMCONFIG));
List<ControlItemConfig> cicList = new List<ControlItemConfig>();
scList = ListSort(scList);
foreach (SerializerContainer sc in scList)
{
ControlItemConfig itemConfig; // = new ControlItemConfig();
itemConfig = DeserializeIt<ControlItemConfig>(sc.Config);
sc.Processed = true;
cicList.Add(itemConfig);
if ((itemConfig.Type == ControlType.Frame))
{
var frameConfig = (FrameConfig)itemConfig.Instance;
if (frameConfig.ChildControls == null)
{
frameConfig.ChildControls = DeserializeFrames(sc.Parent + sc.Name);
}
}
}
return cicList.ToArray();
}
Other smaller methods involved are:
private CommandConfig[] DeserializeCommands(string parent)
{
List<SerializerContainer> scList = list.FindAll(sc => (sc.Parent == parent) &&
(sc.Processed == false) &&
(sc.ConfigType == COMMANDCONFIG));
List<CommandConfig> ccList = new List<CommandConfig>();
scList = ListSort(scList);
foreach (SerializerContainer sc in scList)
{
CommandConfig commandConfig;
commandConfig = DeserializeIt<CommandConfig>(sc.Config);
sc.Processed = true;
ccList.Add(commandConfig);
}
return ccList.ToArray();
}
private VariableConfig[] DeserializeSortedVariables(string parent)
{
List<SerializerContainer> scList = list.FindAll(sc => (sc.Parent == parent) &&
(sc.Processed == false) &&
(sc.ConfigType == VARIABLECONFIG));
List<VariableConfig> ccList = new List<VariableConfig>();
scList = ListSort(scList);
foreach (SerializerContainer sc in scList)
{
VariableConfig variableConfig;
variableConfig = DeserializeIt<VariableConfig>(sc.Config);
sc.Processed = true;
ccList.Add(variableConfig);
}
return ccList.ToArray();
}
private List<SerializerContainer> ListSort(List<SerializerContainer> listParam)
{
List<SerializerContainer> imList = listParam.FindAll(sc => (sc.Source == "XXX"));
List<SerializerContainer> dmList = listParam.FindAll(sc => (sc.Source == "YYY"));
imList.Sort();
dmList.Sort();
SerializerContainer[] scArray = new SerializerContainer[listParam.Count];
//the goal is to use the absolute position value for XXX as set by
//each node's order value. after processing the XXX, process the yyyy data,
//plugging nodes into the array being built in the first open position found starting from
//the front of the array
//iterate through the instrument manager's configuration list from end to start
int idx;
for (int i = imList.Count - 1; i >= 0; i--)
{
//if the config node's order is greater than the number of elements in overall list
//set the index to the point to the last element in the array we are populating;
//otherwise set the index to the node's order value.
if (imList[i].Order >= listParam.Count)
{
idx = listParam.Count - 1;
}
else
{
idx = imList[i].Order - 1;
}
//find a spot in the array that is not occupied and put the node there.
while (scArray[idx] != null)
{
idx--;
}
if (idx >= 0)
{
scArray[idx] = imList[i];
}
else
{
throw new ArgumentOutOfRangeException(@"The index for the configuration list sort operation is less than zero.");
}
}
idx = 0;
//plug im nodes in wherever we find an open spot in the array
foreach (SerializerContainer sc in dmList)
{
while (scArray[idx] != null)
{
idx++;
}
scArray[idx] = sc;
}
return new List<SerializerContainer>(scArray);
}
WindowConfig
? I had the same feeling as @ahybertz, because I did similar deserizalization for one of my projects (XML file like XAML or MXML). The XML can be first parsed to create some DOM (Document Object Model) with possible references which you handle in second pass (usingDictionary<String,Object>
). \$\endgroup\$