Dynamic ObservableCollection in TreeView? - c#

I Have this problem where I can´t load my data into my TreeView but I have to do it manually instead. My static solution looks like this:
public static ObservableCollection<ClassOfDoom> GetAll()
{
ObservableCollection<ClassOfDoom> listToReturn = new ObservableCollection<ClassOfDoom>();
ClassOfDoom treeItem = null;
OUViewModel ouvm = new OUViewModel();
int[] tempOU = ouvm.HierarchyIntOU;
int[] tempP = ouvm.HierarchyIntParent;
treeItem = new ClassOfDoom("Root");
treeItem.cID = tempOU[0];
treeItem.pID = tempP[0];
for (int i = 0; i < ouvm.HierarchyIntParent.Length; i++)
{
if (treeItem.cID == tempP[i])
{
treeItem.ClassOfDooms.Add(new ClassOfDoom(tempOU[i].ToString()));
treeItem.ClassOfDooms.Last().pID = tempP[i];
treeItem.ClassOfDooms.Last().cID = tempOU[i];
for (int i1 = 0; i1 < ouvm.HierarchyIntParent.Length; i1++)
{
if (treeItem.ClassOfDooms.Last().cID == tempP[i1])
{
treeItem.ClassOfDooms.Last().Countries.Add(new ClassOfDoom(tempOU[i1].ToString()));
}
}
}
}
listToReturn.Add(treeItem);
return listToReturn;
}
This works but as you can see it´s only three levels and I wan´t a dynamic amount of levels. If someone wonders my ClassOfDooms list looks like this:
public ObservableCollection<ClassOfDoom> ClassOfDooms
{
get
{
if (classOfDooms == null) classOfDooms = new ObservableCollection<ClassOfDoom>();
return classOfDooms;
}
set { classOfDooms = value; }
}
I want to state again that I have no trouble reading data from my database or anything like that. The TreeView get´s the right information just not all of it.
EDIT: I solved it myself like this:
ClassOfDoom[] asdfDooms = new ClassOfDoom[ouvm.HierarchyIntParent.Length];
for (int i = 0; i < ouvm.HierarchyIntParent.Length; i++)
{
asdfDooms[i] = new ClassOfDoom();
asdfDooms[i].cID = tempOU[i];
asdfDooms[i].pID = tempP[i];
asdfDooms[i].name = tempPersonName + asdfDooms[i].cID.ToString();
}
for (int aint = 0; aint < ouvm.HierarchyIntParent.Length; aint++)
{
for (int i = 0; i < ouvm.HierarchyIntParent.Length; i++)
{
if (asdfDooms[aint].cID == asdfDooms[i].pID)
{
asdfDooms[aint].classOfDooms.Add(asdfDooms[i]);
}
}
}
listToReturn.Add(asdfDooms[0]);

Try implementing the INotifyPropertyChanged interface in conjunction with the HierarchicalDataTemplate control, this should ensure that changes made to the underlying data structure are reflected in the TreeView structure.

Related

Generic hierarchical DataView class with dynamic levels of sort keys

When we create a DataView with sort on multiple columns, we are forced to specify values of all the columns when using FindRows.
Example, if I have:
dv1 = new DataView(tbl1, null, "Col1, Col2, Col3", DataViewRowState.CurrentRows);
I am forced to specify values for all 3 columns when using FindRows.
It is not possible to retrieve all rows for a particular value of Col1 and "any" value for Col2 and Col3.
This is possible in a SortedList where I can have nested SortedList. So, the top level SortedList will have key as Col1, and value as another SortedList. The 2nd level SortedList will have key as Col2, and value as another SortedList. Finally, the 3rd level SortedList will have key as Col3, and the references to the DataRows.
Using such a SortedList, it is possible to write methods, like:
public DataRowView[] FindAny(object[] keys)
where if the keys array contains only 1 key, the code can find the 2nd level SortedList from the 1st level SortedList for the key, and then loop through the 2nd and 3rd level SortedList and return all rows, as they belong to 1st key.
My question is whether anyone has already written such a SortedList class which can take dynamic number of keys, and work with any DataTable / DataRow.
Note:
1. This question has nothing to do with presentation layer. I am looking for a helper class for data processing, say for analysing huge volume of data in multiple excel sheets.
2. I am not looking for a LINQ based solution currently. I will migrate to LINQ in future.
Thanks.
I managed to write my own generic class, which implements a hierarchial view of the data. Improvements in this are welcome.
public class HDataView
{
private SortedList mapDataRows;
int numMapLevels;
public HDataView(DataTable tbl, string[] colNames)
{
object colVal = null;
string colName = "";
SortedList currLvlMap = null, nextLvlMap = null;
DataRow dr1 = null;
ArrayList arlLastLvlData;
mapDataRows = new SortedList();
numMapLevels = colNames.Length;
for (int i = 0; i < tbl.Rows.Count; i++)
{
dr1 = tbl.Rows[i];
currLvlMap = mapDataRows;
for (int j = 0; j < colNames.Length; j++)
{
colName = colNames[j];
colVal = dr1[colName];
if (j == colNames.Length - 1)
{
arlLastLvlData = (ArrayList)currLvlMap[colVal];
if (arlLastLvlData == null)
{
arlLastLvlData = new ArrayList();
currLvlMap[colVal] = arlLastLvlData;
}
arlLastLvlData.Add(dr1);
}
else
{
nextLvlMap = (SortedList)currLvlMap[colVal];
if (nextLvlMap == null)
{
nextLvlMap = new SortedList();
currLvlMap[colVal] = nextLvlMap;
}
//For the next column, the current nextLvlMap will become the prevLvlMap
currLvlMap = nextLvlMap;
}
}
}
}
public ArrayList FindAnyRows(object[] keys)
{
object keyVal = "";
ArrayList arlDataRows = null, arlCurrRows = null;
SortedList startLvlMap = null, currLvlMap = null, nextLvlMap = null;
int mapLevel = 1, startLevel = 0;
currLvlMap = mapDataRows;
mapLevel = 1;
for (int i = 0; i < keys.Length; i++)
{
keyVal = keys[i];
if (currLvlMap == null)
{
break;
}
if (i == numMapLevels - 1)
{
arlDataRows = (ArrayList)currLvlMap[keyVal];
}
else
{
nextLvlMap = (SortedList)currLvlMap[keyVal];
currLvlMap = nextLvlMap;
mapLevel++;
}
}
if (arlDataRows == null)
{
arlDataRows = new ArrayList();
}
if (keys.Length > 0 && keys.Length < numMapLevels)
{
if (currLvlMap != null)
{
startLvlMap = currLvlMap;
startLevel = mapLevel;
if (mapLevel == numMapLevels)
{
for (int j = 0; j < startLvlMap.Count; j++)
{
arlCurrRows = (ArrayList)startLvlMap.GetByIndex(j);
if (arlCurrRows != null)
{
arlDataRows.AddRange(arlCurrRows);
}
}
}
else
{
for (int i = 0; i < startLvlMap.Count; i++)
{
mapLevel = startLevel;
currLvlMap = startLvlMap;
//travel full depth of this map, for each element of this map
for (; mapLevel <= numMapLevels; mapLevel++)
{
if (mapLevel == numMapLevels)
{
for (int j = 0; j < currLvlMap.Count; j++)
{
arlCurrRows = (ArrayList)currLvlMap.GetByIndex(j);
if (arlCurrRows != null)
{
arlDataRows.AddRange(arlCurrRows);
}
}
}
else
{
//Next level of current element of the starting map
nextLvlMap = (SortedList)currLvlMap.GetByIndex(i);
currLvlMap = nextLvlMap;
}
}
}
}
}
}
return arlDataRows;
}
}

Populate TextBoxes from a List

I am trying to populate TextBoxes from a list. I have been able to populate ComboBoxes with comboList:
var comboList = new System.Windows.Forms.ComboBox[4];
comboList[0] = cmbSite1Asset;
comboList[1] = cmbSite2Asset;
comboList[2] = cmbSite3Asset;
comboList[3] = cmbSite4Asset;
List<CRCS.CAsset> assets = _rcs.Assets;
foreach (CRCS.CAsset asset in assets)
{
string id = asset.ID;
for (int i = 0; i < 4; ++i)
{
comboList[i].Items.Add(id);
}
}
But when I try and apply the same principle to TextBoxes
var aosList = new System.Windows.Forms.TextBox[8];
aosList[0] = txtAsset1;
aosList[1] = txtAsset2;
aosList[2] = txtAsset3;
aosList[3] = txtAsset4;
aosList[4] = txtAsset5;
aosList[5] = txtAsset6;
aosList[6] = txtAsset7;
aosList[7] = txtAsset8;
foreach (CRCS.CAsset asset in assets)
{
string id = asset.ID;
for (int n = 0; n < 8; ++n)
{
aosList[n].Items.Add(id);
}
}
TextBox does not like Items.Add ( aosList[n]Items.Add(id); )
I am looking fore a reference or guidance resolving this issue. Thanks!
You should use ComboBox for your problem,instead of iterating on each element,You simply use below lines to populate combobox.
comboList.DataSource=assets;
comboList.DisplayMember="ID";
comboList.ValueMember="ID";
However,if you want your values in TextBox,you can use TextBox.AppendText Method, but it will not work like ComboBox as it will contain texts+texts+texts, will not have indexes like ComboBox.
private void AppendTextBoxLine(string myStr)
{
if (textBox1.Text.Length > 0)
{
textBox1.AppendText(Environment.NewLine);
}
textBox1.AppendText(myStr);
}
private void TestMethod()
{
for (int i = 0; i < 2; i++)
{
AppendTextBoxLine("Some text");
}
}
A Combobox is a collection of items, and so has an Items property from which you can add/remove to change it's contents. A Textbox is just a control that displays some text value, so it has a Text property which you can set/get, and which denotes the string that is displayed.
System.Windows.Forms.TextBox[] aosList = new System.Windows.Forms.TextBox[8];
aosList[0] = txtAsset1;
aosList[1] = txtAsset2;
aosList[2] = txtAsset3;
aosList[3] = txtAsset4;
aosList[4] = txtAsset5;
aosList[5] = txtAsset6;
aosList[6] = txtAsset7;
aosList[7] = txtAsset8;
for (int n = 0; n < 8; ++n)
{
aosList[n].Text = assets[n].ID; // make sure you have 8 assets also!
}
int i = 1;
foreach (var asset in assets)
{
this.Controls["txtAsset" + i].Text = asset.ID;
i++;
}

c# code transfers into QT C++

I want to make a program using COM webbrowser which is a control in C#. In C#,I wrote these code:
myEles = webBrowser1.Document.All;
foreach (HtmlElement myEle in myEles)
{
if (myEle.TagName == myTag)
{
if (i == myIndex)
{
return myEle;
}
i++;
}
}
And I want to transfer it into QT. I've noticed that Qaxobject is essential. But I still got stuck when enum the element in myEles, my attempt code in QT:
int i = 0;
QAxObject* myEles = ui.MyWebView->querySubObject("Document");
myEles = myEles->querySubObject("All");
QAxObject* myEle;
int myCnt = myEles->dynamicCall("Count").toInt();
for (int j = 0;j < myCnt;j++)
{
myEle = myEles->querySubObject("[int]", j);
if(myEle->property("TagName") ==myTag)
{
if (i == myIndex)
{
myEle->dynamicCall("InvokeMember(const QString&)", "click");
return myEle;
}
i++;
}
}
With this, I can't even get the right myCnt . I just wonder how to write it correctly.
I've tried qt foreach,but still....
There is probably no "count" public slot you can call. Check the documentation with myEles->generateDocumentation(); for this.
To iterate through all your properties use the function propertyBag().
You will get a QMap with all properties:
QAxObject* myEles = ui.axWidget->querySubObject("Document");
myEles = myEles->querySubObject("All");
QMap<QString, QVariant> map = myEles->propertyBag();
int myCnt = map.size();
for (int j = 0;j < myCnt;j++)
{
...
}

Why am I getting NullReferenceException when tried to set a value to property array?

I am trying to make a Genetic Algorithm implementation for my thesis. There are two main class: Facility as chromosome and FacilityCell as gene. But I am getting an error while getting the fitness value from Facility class.
The necessary values are set in the Form.cs and after the algorithm has been run, these properties are null in the Facility instance. These properties are Facility.Flows and Facility.Demands. I can't understand why. Please help.
Code part from Form.cs
fac = new Facility();
List<FacilityCell> gens = new List<FacilityCell>();
for (int i = 0; i < 6; i++)
{
gens.Add(new FacilityCell(i.ToString(), i));
}
fac.Genes = gens.ToArray();
fac.Cells = gens.ToArray();
float[] dems = new float[3];
dems[0] = 300;
dems[1] = 60;
dems[2] = 160;
fac.Demands = dems;
FacilityCell[][] fl = new FacilityCell[3][];
fl[0] = new FacilityCell[] {
fac.Cells[0],
fac.Cells[2],
fac.Cells[4],
fac.Cells[1],
fac.Cells[3],
fac.Cells[5] };
fl[1] = new FacilityCell[] {
fac.Cells[2],
fac.Cells[4],
fac.Cells[1],
fac.Cells[5],
fac.Cells[3],
fac.Cells[4] };
fl[2] = new FacilityCell[] {
fac.Cells[1],
fac.Cells[0],
fac.Cells[4],
fac.Cells[2],
fac.Cells[3],
fac.Cells[5] };
fac.Flows = fl;
Code from Facility.cs:
public class Facility : IChromosome
{
public Facility()
{
}
public Facility(FacilityCell[] cells)
{
this.cells = cells;
flows = null;
demands = null;
for (int i = 0; i < cells.Length; i++)
{
cells[i].Order = i;
}
}
private IGene[] cells;
private float[] demands;
private FacilityCell[][] flows;
public FacilityCell[][] Flows
{
get { return flows; }
set { flows = value; }
}
public FacilityCell[] Cells
{
get
{
return cells as FacilityCell[];
}
set
{
cells = value;
}
}
public float[] Demands
{
get { return demands; }
set { demands = value; }
}
public float FitValue
{
get
{
float total = 0;
//I AM GETTING ERROR IN THIS LINE OF CODE, THE FOR LOOP
//It throws NullReferenceException for both this.Demands and this.Flows
for (int i = 0; i < flows.Length; i++)
{
for (int j = 0; j < flows[i].Length - 1; j++)
{
int dist = Math.Abs(flows[i][j + 1].Order - flows[i][j].Order);
float totflow = dist * demands[i];
total += totflow;
}
}
return total;
}
}
public IGene[] Genes
{
get
{
return cells;
}
set
{
cells = value;
}
}
}
This code: FacilityCell[][] fl = new FacilityCell[3][]; will in the constructor set demands to null, You call ths code AFTER you set the demands.

How can I access the ItemsPanel of a ListBox at runtime in silverlight?

How can I access the ItemsPanel of a ListBox at runtime in silverlight?
Given the following element declaration in XAML
<ListBox x:Name="LB" Loaded="LB_Loaded" />
There are two ways to achieve this, the easiest requires the Silverlight toolkit:
using System.Windows.Controls.Primitives;
private void LB_Loaded()
{
var itemsPanel = LB.GetVisualChildren().OfType<Panel>().FirstOrDefault();
}
Or you can use the VisualTreeHelper and write the following recursive method:
T GetFirstChildOfType<T>(DependencyObject visual) where T:DependencyObject
{
var itemCount = VisualTreeHelper.GetChildrenCount(visual);
if (itemCount < 1)
{
return null;
}
for (int i = 0; i < itemCount; i++)
{
var dp = VisualTreeHelper.GetChild(visual, i);
if (dp is T)
{
return (T)dp;
}
}
for (int i = 0; i < itemCount; i++)
{
var dp = GetFirstChildOfType<T>(VisualTreeHelper.GetChild(visual, i));
if (dp != null) return dp;
}
return null;
}
And get the result in a similar manner:
void ItemsPanelSample_Loaded(object sender, RoutedEventArgs e)
{
var itemsPanel = GetFirstChildOfType<Panel>(LB);
}
Building on terphi's solution, i changed it to return a list of the elements you are looking for as normally when your searching for a type, the listbox will have multiple items and multiple instances of what you are looking for. Additionally, I had issues with it finding things in the loaded event but used a dispatcher instead and it finds the items every time in testing.
private List<TextBlock> TextBlockList;
in the constructor, after associating the datasource with listbox:
Dispatcher.BeginInvoke(delegate { TextBlockList = GetFirstChildOfType<TextBlock>(listBox1); });
List<T> GetFirstChildOfType<T>(DependencyObject visual) where T : DependencyObject
{
DependencyObject ControlCandidate;
List<T> TempElements;
List<T> TargetElementList = new List<T>();
var itemCount = VisualTreeHelper.GetChildrenCount(visual);
if (itemCount > 0)
{
for (int i = 0; i < itemCount; i++)
{
ControlCandidate = VisualTreeHelper.GetChild(visual, i);
if (ControlCandidate is T)
TargetElementList.Add((T)ControlCandidate);
}
for (int i = 0; i < itemCount; i++)
{
TempElements = GetFirstChildOfType<T>(VisualTreeHelper.GetChild(visual, i));
if (TempElements.Count > 0)
TargetElementList.AddRange(TempElements);
}
}
return TargetElementList;
}

Categories

Resources