I have a function GetDirectories() which returns me the List of directory info : Now i need to reconstruct a tree view out of it , based on the its parent
Here is my function Getdirectories which return the List:
public List<DirectoryInfo> GetDirectories()
{
DirectoryInfo di = new DirectoryInfo("D:\\python_code");
folders.Clear();
FullDirList(di, "*");
return folders;
}
static List<DirectoryInfo> folders = new List<DirectoryInfo>(); // List that hold direcotries that cannot be accessed
static void GetFullDirList(DirectoryInfo dir, string searchPattern)
{
try
{
foreach (FileInfo f in dir.GetFiles(searchPattern))
{
files.Add(f);
}
}
catch
{
}
foreach (DirectoryInfo d in dir.GetDirectories())
{
folders.Add(d);
FullDirList(d, searchPattern);
}
}
I need something like this to be constructed from the List , which contain all the DirectoryInfo elements i.e it contains its parent info also .
so far i am trying to get the elements whose parent are same and populate it to tree view and do it recursively :
But i am not able to get the recursive function written through .
I know their other easier ways to do the same , but this is a recruitment of a big picture i am trying to draw .
any help would be extremly appretiated .
Assuming you have WinForms treeview you can use the key argument of the Find method on the Nodes collection to build up your hierarchy. You don't need recursion for that. Here is the Add method:
void Add(DirectoryInfo di)
{
if (di.Parent != null )
{
// find our parent node
var node = treeView1.Nodes.Find(di.Parent.FullName,true);
if (node.Length == 0)
{
// not found, add it as root
// FullName becomes the key
treeView1.Nodes.Add(di.FullName, di.Name);
}
else
{
// not sure what is going on if node.Length > 1
// anyway, add it to the first node, to be our parent
node[0].Nodes.Add(di.FullName, di.Name);
}
}
else
{
treeView1.Nodes.Add(di.FullName, di.Name);
}
}
And a simple iterator will drive this method:
var list = GetDirectories();
foreach(var di in list)
{
Add(di);
}
Related
Hello I have function which creates/updates fields in app.exe.config file
public static void UpdateConfig(string FieldName, string FieldValue, ConfigSelector SectionName = ConfigSelector.AppSettings)
{
switch (SectionName)
{
case ConfigSelector.Execption:
{
// MessageBox.Show("gg");
var xmlDoc = new XmlDocument();
xmlDoc.Load(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
if (xmlDoc.SelectSingleNode("configuration/Execption") != null)
{
if (xmlDoc.SelectSingleNode("configuration/Execption/List") != null)
{
// create new node <add key="Region" value="Canterbury" />
var nodeRegion = xmlDoc.CreateElement("add");
nodeRegion.SetAttribute("key", FieldName);
nodeRegion.SetAttribute("value", FieldValue);
xmlDoc.SelectSingleNode("configuration/Execption/List").AppendChild(nodeRegion);
}
else
{
var List = xmlDoc.CreateElement("List");
xmlDoc.SelectSingleNode("configuration/Execption").AppendChild(List);
UpdateConfig(FieldName, FieldValue, SectionName);
}
}
else
{
var List = xmlDoc.CreateElement("Execption");
xmlDoc.SelectSingleNode("configuration").AppendChild(List);
UpdateConfig(FieldName, FieldValue, SectionName);
}
xmlDoc.Save(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
ConfigurationManager.RefreshSection("Execption/List");
break;
}
}
}
Function works first Check if xpath configuration/Execption exist, if not exist it creates this path and recalls function again, second time check if configuration/Execption/List path exist if not creates path and recalls function again, and third time adds required fields which is fieldname and fieldvalue,
but I getting System.StackOverflowException in line:
if (xmlDoc.SelectSingleNode("configuration/Execption") != null)
Did I miss something?
You are calling UpdateConfig recursively, with the exact same arguments already passed to it
UpdateConfig(FieldName, FieldValue, SectionName);
Since the recursive call happens before the xmlDoc.Save(), it always works on the same content.
Saving before doing the recursive call should fix the issue.
You don't save the document after adding the new element, so when you are loading the file in the next iteration the new element isn't there, and xmlDoc.SelectSingleNode("configuration/Execption") != null is still false, so the code creates the element again in infinite recursion and you get StackOverflowException.
Just save the document after you change it
else
{
var List = xmlDoc.CreateElement("Execption");
xmlDoc.SelectSingleNode("configuration").AppendChild(List);
xmlDoc.Save(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
UpdateConfig(FieldName, FieldValue, SectionName);
}
I'm trying to write an xml parser to take some data in a game and build out objects for me. Right now I want to go through the nodes and build out different config objects based on the node/attributes.
foreach (XmlNode node in actionList) {
ActionConfig config;
if (some checks determine action is "Fire") {
config = new FireActionConfig();
config.speed = (float)node.Attributes["speed"].Value;
}
// do something with config
}
The error I get is "ActionConfig does not contain a definition for speed...". I tried casting config as FireActionConfig even though it's already defined as one.
foreach (XmlNode node in actionList) {
ActionConfig config;
if (some checks determine action is "Fire") {
FireActionConfig fireConfig = new FireActionConfig();
fireConfig.speed = Single.Parse( node.Attributes["speed"].Value );
config = fireConfig;
}
// do something with config
}
I have a flat file that looks like this:
.root:NODE
.root.branch1:NODE
.root.branch1.size:INT
.root.branch1.name:STRING
.root.branch2:NODE
.root.branch2.flavor:NODE
.root.branch2.flavor.cost:INT
.root.branch2.flavor.name:STRING
The file contents, depth, lenght, etc., will be different every time, so I can't hardcode anything (though the nodes will always be of datatype 'NODE'). I need to bring it into C# as a data source. I'm not sure what the best way to parse the file is to convert it to a structure that looks like
+root
+branch1
size:
name:
+branch2
+flavor
cost:
name:
etc. Ideally, I'd like to dynamically build a treeview control that the user can use to select the node he'd like to access (these tags are paths to an actual datasource; so elsewhere in the code, I'm using)
int iVal = somefunction.readvar(".root.branch2.flavor.cost");
/edit/ if it helps, the file I'm trying to parse is a *.SYM file (a symbols file) generated by a TwinCat 2 program. There's a little documentation here: http://infosys.beckhoff.com/content/1033/tcplccontrol/html/tcplcctrl_componentsoptions.htm#Symbol%20configuration
C# :
private void AddToTreeView()
{
TreeViewItem root = new TreeViewItem();
foreach (string line in ReadLines())
{
var parts = line.Split(new char[] { '.' },StringSplitOptions.RemoveEmptyEntries);
if (parts.Length == 1)
{
root.Header = parts[0].Split(':')[0];
root.Tag = line;
}
else
{
TreeViewItem node = root;
foreach (var part in parts)
{
var header = part.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries)[0];
if(!IfExists(node, header, ref node))
{
node.Items.Add(new TreeViewItem()
{
Header = header,
Tag = line
});
node = root;
}
}
}
}
treeView.Items.Add(root);
}
private bool IfExists(TreeViewItem itm, string header, ref TreeViewItem which)
{
if (itm.Header as string == header)
{
which = itm;
return true;
}
foreach (TreeViewItem i in itm.Items)
{
if (i.Header as string == header)
{
which = i;
return true;
}
else if (i.HasItems)
{
if (IfExists(i, header, ref which))
return true;
}
}
return false;
}
XAML:
<TreeView x:Name="treeView" Height="100">
</TreeView>
Screenshot:
Well, this code works but, it may have some flaws and it is not a perfect solution. Anyway, even it doesn't work perfectly, it should help you in some ways.
EDİT:
This way, it sometimes doesn't work, e.g. if the nodes isn't ordered.
I changed this part of the program so it should have no other errors anymore.
if (!IfExists(node, header, ref node))
{
var currNode = new TreeViewItem()
{
Header = header,
Tag = line
};
node.Items.Add(currNode);
if (part.Contains(":"))
node = root;
else
node = currNode;
}
The previous code's output if input is:
.root:NODE
.root.branch1:NODE
.root.branch2.flavor.name:STRING
.root.branch1.size:INT
.root.branch1.name:STRING
.root.branch2:NODE
.root.branch2.flavor:NODE
.root.branch2.flavor.cost:INT
But with the changed code, it gives output exactly as it should!
Trying to figure out why this isn't working, the list is to retrieve photos using the combobox item (which lists local HDDs root address as items) when selected that item it is converted into a string and supposed to be used as a path for the GetFiles Method but screws up on the (string path = ) line when running, I get "object reference not set to instance of an object" much appreciated If someone could tell me what is going wrong
public List<Photos> LoadImages ///List Retrieves and Loads Photos
{
get
{
List<Photos> Image = new List<Photos>();
string path = HDDSelectionBox.SelectedItem.ToString(); //ComboBox SelectedItem Converted To String As Path
foreach (string filename in Directory.GetFiles(path, "*jpg"))
{
try
{
Image.Add( //Add To List
new Photos(
new BitmapImage(
new Uri(filename)),
System.IO.Path.GetFileNameWithoutExtension(filename)));
}
catch { } //Skips Any Image That Isn't Image/Cant Be Loaded
}
return Image;
}
}
You should put . before the file extension in the line:
Directory.GetFiles(path, "*.jpg")
You also need to check if HDDSelectionBox.SelectedItem is not null:
public List<Photos> LoadImages ///List Retrieves and Loads Photos
{
get
{
List<Photos> images = new List<Photos>();
if (HDDSelectionBox.SelectedItem != null)
{
string path = HDDSelectionBox.SelectedItem.ToString(); //ComboBox SelectedItem Converted To String As Path
foreach (string filename in Directory.GetFiles(path, "*.jpg"))
{
try
{
images.Add( //Add To List
new Photos(
new BitmapImage(
new Uri(filename)),
System.IO.Path.GetFileNameWithoutExtension(filename)));
}
catch { } //Skips Any Image That Isn't Image/Cant Be Loaded
}
}
return images;
}
}
Also, this is probably better suited to a method rather than a property as it does quite a lot of processing...
This is what my team and I chose to do for our school project. Well, actually we haven't decided on how to parse the C# source files yet.
What we are aiming to achieve is, perform a full analysis on a C# source file, and produce up a report.
In which the report is going to contain stuff that happening in the codes.
The report only has to contain:
string literals
method names
variable names
field names
etc
I'm in charge of looking into this Irony library. To be honest, I don't know the best way to sort the data out into a clean readable report. I am using the C# grammar class packed with the zip.
Is there any step where I can properly identify each node children? (eg: using directives, namespace declaration, class declaration etc, method body)
Any help or advice would be very much appreciated. Thanks.
EDIT: Sorry I forgot to say we need to analysis the method calls too.
Your main goal is to master the basics of formal languages. A good start-up might be found here. This article describes the way to use Irony on the sample of a grammar of a simple numeric calculator.
Suppose you want to parse a certain file containing C# code the path to which you know:
private void ParseForLongMethods(string path)
{
_parser = new Parser(new CSharpGrammar());
if (_parser == null || !_parser.Language.CanParse()) return;
_parseTree = null;
GC.Collect(); //to avoid disruption of perf times with occasional collections
_parser.Context.SetOption(ParseOptions.TraceParser, true);
try
{
string contents = File.ReadAllText(path);
_parser.Parse(contents);//, "<source>");
}
catch (Exception ex)
{
}
finally
{
_parseTree = _parser.Context.CurrentParseTree;
TraverseParseTree();
}
}
And here is the traversal method itself with counting some info in the nodes. Actually this code counts the number of statements in every method of the class. If you have any question you are always welcome to ask me
private void TraverseParseTree()
{
if (_parseTree == null) return;
ParseNodeRec(_parseTree.Root);
}
private void ParseNodeRec(ParseTreeNode node)
{
if (node == null) return;
string functionName = "";
if (node.ToString().CompareTo("class_declaration") == 0)
{
ParseTreeNode tmpNode = node.ChildNodes[2];
currentClass = tmpNode.AstNode.ToString();
}
if (node.ToString().CompareTo("method_declaration") == 0)
{
foreach (var child in node.ChildNodes)
{
if (child.ToString().CompareTo("qual_name_with_targs") == 0)
{
ParseTreeNode tmpNode = child.ChildNodes[0];
while (tmpNode.ChildNodes.Count != 0)
{ tmpNode = tmpNode.ChildNodes[0]; }
functionName = tmpNode.AstNode.ToString();
}
if (child.ToString().CompareTo("method_body") == 0) //method_declaration
{
int statementsCount = FindStatements(child);
//Register bad smell
if (statementsCount>(((LongMethodsOptions)this.Options).MaxMethodLength))
{
//function.StartPoint.Line
int functionLine = GetLine(functionName);
foundSmells.Add(new BadSmellRegistry(name, functionLine,currentFile,currentProject,currentSolution,false));
}
}
}
}
foreach (var child in node.ChildNodes)
{ ParseNodeRec(child); }
}
I'm not sure this is what you need but you could use the CodeDom and CodeDom.Compiler namespaces to compile the C# code, and than analyze the results using Reflection, something like:
// Create assamblly in Memory
CodeSnippetCompileUnit code = new CodeSnippetCompileUnit(classCode);
CSharpCodeProvider provider = new CSharpCodeProvider();
CompilerResults results = provider.CompileAssemblyFromDom(compileParams, code);
foreach(var type in results.CompiledAssembly)
{
// Your analysis go here
}
Update: In VS2015 you could use the new C# compiler (AKA Roslyn) to do the same, for example:
var root = (CompilationUnitSyntax)tree.GetRoot();
var compilation = CSharpCompilation.Create("HelloTDN")
.AddReferences(references: new[] { MetadataReference.CreateFromAssembly(typeof(object).Assembly) })
.AddSyntaxTrees(tree);
var model = compilation.GetSemanticModel(tree);
var nameInfo = model.GetSymbolInfo(root.Usings[0].Name);
var systemSymbol = (INamespaceSymbol)nameInfo.Symbol;
foreach (var ns in systemSymbol.GetNamespaceMembers())
{
Console.WriteLine(ns.Name);
}