I'm trying to build simple sql query editor, I need to be able to edit query conditions (part after WHERE keyword).
I have tree that shows conditions as shown below:
I have problem with transforming nodes to proper SQL code.
I can iterate over nodes, but this gives me below result:
AND
Name = John
OR
Surname = Smith
Lastname = Smith
But I need this (valid SQL):
Name = John
AND
(
Surname = Smith
OR
Lastname = Smith
)
How can I do that?
Here is code that I used to extend TreeNode and to create sample from screenshot:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
var root = new OperatorNode(OperatorType.AND);
var treeNode = new SqlTextNode("Name", ContitionType.EQUAL, "John");
root.Nodes.Add(treeNode);
var orNode = new OperatorNode(OperatorType.OR);
var node2 = new SqlTextNode("Surname",ContitionType.EQUAL, "Smith");
var node3 = new SqlTextNode("Lastname",ContitionType.EQUAL, "Smith");
orNode.Nodes.Add(node2);
orNode.Nodes.Add(node3);
root.Nodes.Add(orNode);
treeView1.Nodes.Add(root);
treeView1.ExpandAll();
}
private void button1_Click(object sender, EventArgs e)
{
CallRecursive(treeView1);
}
private void PrintRecursive(TreeNode treeNode)
{
Debug.WriteLine(treeNode.Text);
foreach (TreeNode tn in treeNode.Nodes)
{
PrintRecursive(tn);
}
}
private void CallRecursive(TreeView treeView)
{
TreeNodeCollection nodes = treeView.Nodes;
foreach (TreeNode n in nodes)
{
PrintRecursive(n);
}
}
}
public class OperatorNode : TreeNode
{
private OperatorType _operator;
public OperatorType Operator
{
get { return _operator; }
set
{
if(value==_operator) return;
_operator = value;
Text = _operator.ToString();
}
}
public OperatorNode(OperatorType #operator) : base(#operator.ToString())
{
_operator = #operator;
}
}
public class SqlTextNode : TreeNode
{
private string _fieldName;
private ContitionType _condition;
private string _value;
public SqlTextNode(string fieldName, ContitionType condition, string value)
{
_fieldName = fieldName;
_condition = condition;
_value = value;
UpdateText();
}
public string FieldName
{
get { return _fieldName; }
set
{
if (value == _fieldName) return;
_fieldName = value;
UpdateText();
}
}
public ContitionType Condition
{
get { return _condition; }
set
{
if (value == _condition) return;
_condition = value;
UpdateText();
}
}
public string Value
{
get { return _value; }
set
{
if (value == _value) return;
_value = value;
UpdateText();
}
}
private void UpdateText()
{
Text = string.Format("{0} {1} {2}", _fieldName, Enums.GetEnumDescription(_condition), _value);
}
}
public enum OperatorType
{
AND,
OR
}
public enum ContitionType
{
EQUAL,
NOT_EQUAL
}
public static class Enums
{
public static string GetEnumDescription(Enum value)
{
FieldInfo fi = value.GetType().GetField(value.ToString());
DescriptionAttribute[] attributes =
(DescriptionAttribute[])fi.GetCustomAttributes(
typeof(DescriptionAttribute),
false);
return attributes.Length > 0 ? attributes[0].Description : value.ToString();
}
}
There are two different types of nodes: OperatorNode and SqlTextNode. You can easily check the type of the node and execute the corresponding actions:
If the node is SqlTextNode just print it as you did it before.
If the node is OperatorNode you need to cover all children with () and insert the operator between them.
This algorithm can be implemented in many different ways but I will add a simple example:
private void PrintRecursive(TreeNode treeNode, int indentation)
{
var indent = new string(' ', indentation * IndentSize);
// SqlTextNode doesn't have children
if (treeNode is SqlTextNode)
Debug.WriteLine(indent + treeNode.Text);
else
{
Debug.WriteLine(indent + "(");
for (int i=0; i<treeNode.Nodes.Count; i++ )
{
PrintRecursive(treeNode.Nodes[i], indentation+1);
if (i!=treeNode.Nodes.Count-1)
{
// print the operator
indent = new string(' ', (indentation+1) * IndentSize);
Debug.WriteLine(indent + treeNode.Text);
}
}
Debug.WriteLine(indent + ")");
}
}
If you want to add indentation into the final query you could pass throuh the reqursion function (CallRecursive) as a parameter and increase it when you need.
This is my version of answer:
I've overridden ToString in my custom node types:
public class OperatorNode : TreeNode
{
private OperatorType _operator;
public OperatorType Operator
{
get { return _operator; }
set
{
if(value==_operator) return;
_operator = value;
Text = _operator.ToString();
}
}
public OperatorNode(OperatorType #operator) : base(#operator.ToString())
{
_operator = #operator;
}
public override string ToString()
{
List<string> n = (from TreeNode node in Nodes select node.ToString()).ToList();
return " ( " + string.Join(Environment.NewLine + _operator + " ", n) + " ) ";
}
}
public class SqlTextNode : TreeNode
{
private string _fieldName;
private ContitionType _condition;
private string _value;
public SqlTextNode(string fieldName, ContitionType condition, string value)
{
_fieldName = fieldName;
_condition = condition;
_value = value;
UpdateText();
}
public override string ToString()
{
return string.Format("{0} {1} {2}", _fieldName, _condition.GetDescription(), _value);
}
public string FieldName
{
get { return _fieldName; }
set
{
if (value == _fieldName) return;
_fieldName = value;
UpdateText();
}
}
public ContitionType Condition
{
get { return _condition; }
set
{
if (value == _condition) return;
_condition = value;
UpdateText();
}
}
public string Value
{
get { return _value; }
set
{
if (value == _value) return;
_value = value;
UpdateText();
}
}
private void UpdateText()
{
Text = string.Format("{0} {1} {2}", _fieldName, _condition.GetDescription(), _value);
}
}
This way each node has logic responsible for creating query parts.
Having that I can generate full query using below function:
private void PrintQuery(TreeView treeView)
{
string s = string.Empty;
TreeNodeCollection nodes = treeView.Nodes;
s = nodes.Cast<TreeNode>().Aggregate(s, (current, n) => current + (n.ToString() + Environment.NewLine)).Trim();
//remove unwanted brackets
s = s.Remove(s.Length - 1).Substring(1).Trim();
textBox1.Text = s;
}
Output doesn't have indentations, but I don't have to show final query, this is just temporary for debug.
I'm aware that I must escape conditions values with single quotes, but that's the easy part :)
Related
This is my implementation for BST (Binary Search Tree). Can Anyone help me to create two methods, one to Connect Leafs and one to return a List of Nodes around the Tree, for example: Connecting Leaf Example In this picture it shows how the leafs should be connected, Nodes that should be stored in List and the way the nodes stored in List need to be in this way where the root is the first element and going to the left passing down to leafs going back to root from the right. In my example it should be 8(root), 3, 1, 4, 7, 13, 14, 10, 8(root).
Thank You!
**class Node
{
private int VL;
private int Niv;
public Node Parent, LC, RC;
public Node()
{
this.Parent = this.LC = this.RC = null;
this.Niv = -1;
}
public Node(int x)
{
this.VL = x;
this.Parent = this.LC = this.RC = null;
this.Niv = -1;
}
public int Vlera
{
get { return this.VL; }
set { this.VL = value; }
}
public int Niveli
{
get { return this.Niv; }
set { this.Niv = value; }
}
}
class BSTree
{
public Node Root;
private int MaxNiv;
public BSTree()
{
this.Root = null;
this.MaxNiv = -1;
}
public void Insert(int x)
{
Node tmp = new Node(x);
if (this.Root == null)
{
tmp.Niveli = 0;
this.Root = tmp;
}
else InsertNode(tmp);
if (tmp.Niveli > this.MaxNiv) MaxNiv = tmp.Niveli;
}
public void ConnectLeafs()
{
//TODO
}
public List<T> ReturnNodesAroundTheTree()
{
//TODO
}
public Node GoTo_Node(Node nd)
{
return GoTo_Node_Rec(this.Root, nd);
}
public Node GoTo_Node(int x)
{
return GoTo_Node_Rec(this.Root, x);
}
private Node GoTo_Node_Rec(Node root, Node nd)
{
if (root.Vlera == nd.Vlera) return root;
if (root.Vlera > nd.Vlera) return GoTo_Node_Rec(root.LC, nd);
else return GoTo_Node_Rec(root.RC, nd);
}
private Node GoTo_Node_Rec(Node root, int x)
{
if (root.Vlera == x) return root;
if (root.Vlera > x) return GoTo_Node_Rec(root.LC, x);
else return GoTo_Node_Rec(root.RC, x);
}
private void InsertNode(Node nd)
{
Node tmp = InsertRecNode(this.Root, nd.Vlera);
if (nd.Vlera >= tmp.Vlera) tmp.RC = nd;
else tmp.LC = nd;
nd.Parent = tmp;
nd.Niveli = nd.Parent.Niveli++;
//if (nd.Niveli > this.MaxNiv) MaxNiv = nd.Niveli;
}
private Node InsertRecNode(Node root, int x)
{
if (x >= root.Vlera)
if (root.RC != null) return InsertRecNode(root.RC, x);
else return root;
else
if (root.LC != null) return InsertRecNode(root.LC, x);
else return root;
}
private bool IsRoot(Node nd)
{
if (nd.Parent == null) return true;
return false;
}
private bool IsLeaf(Node nd)
{
if (nd.LC == null && nd.RC == null) return true;
return false;
}**
Here is the easy way to do this. I created a List of all the node. When you create a new node add node to list. See code below
class BSTree
{
public Node Root;
private int MaxNiv;
private List<Node> nodes = new List<Node>();
public BSTree()
{
this.Root = null;
this.MaxNiv = -1;
}
public void Insert(int x)
{
Node tmp = new Node(x);
nodes.Add(tmp);
if (this.Root == null)
{
tmp.Niveli = 0;
this.Root = tmp;
}
else InsertNode(tmp);
if (tmp.Niveli > this.MaxNiv) MaxNiv = tmp.Niveli;
}
public void ConnectLeafs()
{
//TODO
}
public List<Node> ReturnNodesAroundTheTree()
{
return nodes.Where(x => IsLeaf(x)).ToList();
}
}
In my case, while calling API (GET Method), I should send the below query as part of the body.
URI : GET XXX/_search
Body:
{
"query":
{
"match_all":
{
}
}
}
As of now, I'm hard-coding the string and appending to the resource body.
hopefully below code snippet can help you.
Consumer:
JsonField jsn1 = new JsonField() { Name = "_id"};
jsn1.AddValue("1234");
JsonField jsn2 = new JsonField() { Name = "_name" };
jsn2.AddValue("CDE");
JsonField jsn0 = new JsonField(true) { Name = "match" };
JsonField jsn = new JsonField(true) { Name = "query" };
JsonConverter.MapField(jsn0, jsn1);
JsonConverter.MapField(jsn, jsn0);
JsonConverter jsonconverter = new JsonConverter();
jsonconverter.Add(jsn);
JsonField jsn3 = new JsonField() { Name = "name" };
jsn3.AddValue("temp");
jsonconverter.Add(jsn3);
Console.WriteLine(jsonconverter.GetJsonFormat());
Check logic below.
public class JsonConverter
{
LinkedList<JsonField> jsonlinking = new LinkedList<JsonField>();
public void Add(JsonField jsonfield)
{
LinkedListNode<JsonField> jsonelement = jsonlinking.Last;
if (jsonelement != null)
{
jsonelement.Value.SpecialChar = ",";
}
jsonlinking.AddLast(jsonfield);
}
public string GetJsonFormat()
{
jsonformat = string.Empty;
jsonformat += "{" + Environment.NewLine;
foreach (var item in jsonlinking)
{
ReadJson(item);
}
jsonformat += Environment.NewLine + "}" + Environment.NewLine;
return jsonformat;
}
public static void MapField(JsonField primary, JsonField relative)
{
primary.Next = relative;
}
public static void MapField(Queue<JsonField> linksource)
{
JsonField primary = null;
JsonField relative = null;
foreach (var item in linksource)
{
if (primary == null)
{
primary = item;
}
else if (relative == null)
{
relative = null;
}
else
{
JsonConverter.MapField(primary, relative);
primary = null;
relative = null;
}
}
}
private string jsonformat = string.Empty;
private void ReadJson(JsonField field)
{
if (field != null)
{
jsonformat += #"""";
jsonformat += field.Name;
jsonformat += #"""";
if (field.isContainer)
{
jsonformat += #":{" + Environment.NewLine;
int count = field.ChildNodes.Count();
if (count > 0)
{
foreach (var item in field.ChildNodes)
{
ReadJson(item);
}
}
jsonformat = (jsonformat.Substring(jsonformat.Length - 1, 1) == ",") ? jsonformat.Substring(0, jsonformat.Length - 1) : jsonformat;
jsonformat += #"}" + field.SpecialChar + Environment.NewLine;
}
else
{
jsonformat += #":";
jsonformat += field.GetValues();
}
}
}
}
public class JsonField
{
private int Size = 1;
private int CurrentIndex = 0;
public string Name { get; set; }
private string[] _value;
public string[] Value { get { return _value; } private set { _value = value; } }
public bool isContainer{get;set;}
public JsonField()
{
this.Value = new string[this.Size];
}
private Queue<JsonField> _next = new Queue<JsonField>();
public JsonField Next {
set
{
if (this._next.Count>0)
{
foreach (var item in this._next)
{
item.SpecialChar = ",";
}
}
this._next.Enqueue(value);
}
}
public IEnumerable<JsonField> ChildNodes { get { return this._next; } }
public JsonField(int valuesize)
{
this.Size = valuesize;
this.Value = new string[this.Size];
}
public JsonField(bool iscontainer)
{
this.isContainer = iscontainer;
}
public void AddValue(string value)
{
if (CurrentIndex >= this.Value.Length)
{
throw new ArgumentException("Index Out of Range over Value Array");
return;
}
this.Value[CurrentIndex] = value;
CurrentIndex++;
}
public void ClearValue()
{
this.Value = null;
this.Value = new string[this.Size];
}
public string GetValues()
{
if (this.Value.Length == 1)
{
return #"""" + this.Value[0] + #"""";
}
string returns=string.Empty;
for (int index = 0; index < this.Value.Length; index++)
{
returns += #"""" + this.Value[index] + #"""";
if ((index +1) < this.Value.Length)
{
returns += ",";
}
}
return "[" + returns+ "]";
}
public string SpecialChar { get; set; }
}
I have created tow custom controls to use bootstrap in my C# code. The first one implement a bootstrap dropdown list with this code ;
using System.Web.UI;
using System.Web.UI.WebControls;
using static JDBootStrap.BSTypes;
namespace JDBootStrap.Components
{
[ToolboxData("<{0}:BSDropDown runat=server></{0}:BSDropDown>")]
public class BSDropDown : Panel
{
public enum OrientationType { Down, Up, Right }
string _text;
OrientationType _orientation;
ControlCollection _controls;
sizeType _size = sizeType.md;
bool _useInGroup;
bool useInList;
Glyphicon.GlyphiconType? _glyphicon;
string _style;
public BSDropDown()
{
Controls = new ControlCollection(this);
}
public Glyphicon.GlyphiconType? Glyphicon
{
get
{
return _glyphicon;
}
set
{
_glyphicon = value;
}
}
#region Properties
protected override string TagName
{
get
{
return UseInList ? "li" : "div";
}
}
protected override ControlCollection CreateControlCollection()
{
return Controls;
}
public string Text
{
get
{
return _text;
}
set
{
_text = value;
}
}
public OrientationType Orientation
{
get
{
return _orientation;
}
set
{
_orientation = value;
}
}
public bool UseInList
{
get
{
return useInList;
}
set
{
useInList = value;
}
}
new public ControlCollection Controls
{
get
{
return _controls;
}
set
{
_controls = value;
}
}
public sizeType Size
{
get
{
return _size;
}
set
{
_size = value;
}
}
public bool UseInGroup
{
get
{
return _useInGroup;
}
set
{
_useInGroup = value;
}
}
#endregion
public override void RenderBeginTag(HtmlTextWriter writer)
{
writer.Write("<" + TagName + " class=\"" + GetOrientationClass());
if (_orientation == OrientationType.Right) writer.Write(" dropdown-submenu");
if (!string.IsNullOrEmpty(CssClass)) writer.Write(" " + CssClass);
if (_useInGroup) writer.Write(" btn-group");
writer.Write(" btn-" + (UseInGroup ? "group-" : "") + _size.ToString().ToLower());
writer.Write("\"");
writer.Write(" name =\"" + UniqueID + "\"");
writer.Write(" id=\"" + ClientID + "\"");
writer.Write(">");
writer.Write(UseInList ? "<a href =\"#\"" : "<button");
writer.Write(" class=\"");
writer.Write(_useInGroup ? "btn btn-default " : "");
writer.Write("dropdown-toggle");
writer.Write("\" data-toggle=\"dropdown\" role=\"button\" aria-haspopup=\"true\" aria-expanded=\"false\">");
if (!string.IsNullOrEmpty(_text)) writer.WriteEncodedText(_text);
if (_glyphicon != null)
{
var g = new Glyphicon((Glyphicon.GlyphiconType)_glyphicon);
g.RenderControl(writer);
}
if (_orientation != OrientationType.Right) writer.Write("<span class=\"caret\" style=\"margin-left:4px;\"></span>");
writer.Write(UseInList ? "</a>" : "</button>");
writer.Write("<ul class=\"dropdown-menu\">");
}
protected override void Render(HtmlTextWriter writer)
{
RenderBeginTag(writer);
RenderChildren(writer);
RenderEndTag(writer);
}
protected override void RenderChildren(HtmlTextWriter writer)
{
foreach (Control ctrl in Controls)
{
if (ctrl.GetType() == typeof(BSDropDown)) ((BSDropDown)ctrl).Orientation = OrientationType.Right;
if (ctrl.GetType() == typeof(BSMenuItem)) ((BSMenuItem)ctrl).SubMenu = true;
ctrl.RenderControl(writer);
}
}
public override void RenderEndTag(HtmlTextWriter writer)
{
writer.Write("</ul>");
writer.Write("</" + TagName + ">");
}
private string GetOrientationClass()
{
switch (Orientation)
{
case OrientationType.Up:
return "dropup";
default:
return "dropdown";
}
}
}
}
the second one is a menuitem like this :
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace JDBootStrap.Components
{
[ToolboxData("<{0}:BSMenuSeparator runat=server></{0}:BSMenuSeparator>")]
public class BSMenuSeparator : WebControl
{
protected override void Render(HtmlTextWriter writer)
{
writer.Write("<li class=\"divider\"></li>");
}
}
[ToolboxData("<{0}:BSMenuHeader runat=server></{0}:BSMenuHeader>")]
public class BSMenuHeader : WebControl
{
private string _title;
public BSMenuHeader(string title)
{
_title = title;
}
public string Title
{
get
{
return _title;
}
set
{
_title = value;
}
}
protected override void Render(HtmlTextWriter writer)
{
writer.Write("<li class=\"dropdown-header\">");
if (!string.IsNullOrEmpty(_title)) writer.Write(_title);
writer.Write("</li>");
}
}
[ToolboxData("<{0}:BSMenuItem runat=server></{0}:BSMenuItem>")]
public class BSMenuItem : Panel, IButtonControl, IPostBackEventHandler
{
string _text;
string _navigateUrl;
bool _active ;
b
ool _subItem;
Glyphicon.GlyphiconType? _glyphicon;
string _value;
string _title;
string _commandArgument;
string _validationGroup;
string _postBackUrl;
string _commandName;
bool _causesValidation;
static readonly object EventClick = new object();
public event EventHandler Click
{
add
{
Events.AddHandler(EventClick, value);
}
remove
{
Events.RemoveHandler(EventClick, value);
}
}
public event CommandEventHandler Command;
#region Property
public BSMenuItem()
{
}
public BSMenuItem(string text)
{
_text = text;
}
public BSMenuItem(string text, string navigateUrl)
{
_text = text;
_navigateUrl = navigateUrl;
}
public string Text
{
get
{
return _text;
}
set
{
_text = value;
}
}
public string NavigateUrl
{
get
{
return _navigateUrl;
}
set
{
_navigateUrl = value;
}
}
public bool Active
{
get
{
return _active;
}
set
{
_active = value;
}
}
public bool SubMenu
{
get
{
return _subItem;
}
set
{
_subItem = value;
}
}
public Glyphicon.GlyphiconType? Glyphicon
{
get
{
return _glyphicon;
}
set
{
_glyphicon = value;
}
}
public bool CausesValidation
{
get
{
return _causesValidation;
}
set
{
_causesValidation = value;
}
}
public string CommandArgument
{
get
{
return _commandArgument;
}
set
{
_commandArgument = value;
}
}
public string ValidationGroup
{
get
{
return _validationGroup;
}
set
{
_validationGroup = value;
}
}
public string PostBackUrl
{
get
{
return _postBackUrl;
}
set
{
_postBackUrl = value;
}
}
public string CommandName
{
get
{
return _commandName;
}
set
{
_commandName = value;
}
}
public string Value
{
get
{
return _value;
}
set
{
_value = value;
}
}
public string Title
{
get
{
return _title;
}
set
{
_title = value;
}
}
#endregion
protected override void Render(HtmlTextWriter writer)
{
if (Controls.Count == 0)
{
writer.Write("<li");
writer.Write(" name =\"" + UniqueID + "\"");
writer.Write(" id=\"" + ClientID+"\"");
if (_active) writer.Write(" class=\"active\"");
writer.Write("><a href=\"");
writer.WriteEncodedUrl(NavigateUrl ?? "#");
writer.Write("\"");
if (Events != null) writer.Write(" OnClick=\"" + Page.ClientScript.GetPostBackEventReference(this, Value)+"\"");
if (Title != null) writer.Write(" title=\"" + Title + "\"");
writer.Write(">");
if (Glyphicon!=null)
{
var g = new Glyphicon((Glyphicon.GlyphiconType)_glyphicon);
g.RenderControl(writer);
}
if (!string.IsNullOrEmpty(_text)) writer.WriteEncodedText(_text);
writer.Write("</a></li>");
}
else
{
var dd = new BSDropDown
{
Text = _text,
UseInList = true
};
if (SubMenu) dd.Orientation = BSDropDown.OrientationType.Right;
dd.Controls=Controls;
dd.RenderControl(writer);
}
}
protected virtual void OnClick(EventArgs e)
{
EventHandler handler = (EventHandler)Events[EventClick];
handler?.Invoke(this, e);
}
protected virtual void OnCommand(CommandEventArgs e)
{
Command?.Invoke(this, e);
}
public void RaisePostBackEvent(string eventArgument)
{
OnClick(new EventArgs());
OnCommand(new CommandEventArgs(CommandName, CommandArgument));
}
}
If i use my menu item alone, or as a child of my drop-down control using my aspx page to set them, it work fine. But if i create them programmatically my RaisePostBackEvent is never fired. __EventTarget is well set but nothing happen.
It work only if i set in my aspx page my dropdown and add my child programmatically... (I add my control in Page_init). Thanks for your help.
I use an array of control to override Controls of my dropdown list. If i remove this collection and use inherited Controls properties it work.
I was using my own array because my menuitem can change behaviour and become dropdown list if there is child. So i have to move control child from menuitem to a dropdown (list and Controls can't be set).
Now i have to move control like this :
int l = Controls.Count;
for (int a = 0; a < l; a++)
dd.Controls.Add(Controls[0]);
Controls.Clear();
Controls.Add(dd);
where dd is my new dropdown list. Hope it can help someone.
I have the following Class...
class gridRecord
{
//Constructor
public gridRecord()
{
Quantity = new quantityField();
Title = new titleField();
Pages = new pagesField();
}
private quantityField quantity;
private titleField title;
private pagesField pages;
internal quantityField Quantity
{
get { return quantity; }
set { quantity = value; }
}
internal titleField Title
{
get { return title; }
set { title = value; }
}
internal pagesField Pages
{
get { return pages; }
set { pages = value; }
}
}
I want to be able to get the name of each field as a string so I can later create a datable with out having to specify each column.
List<gridRecord> lgr = new List<gridRecord>();
lgr = populatedList();
foreach(gridField gf in lgr[0])
MessageBox.Show(gf.ToString());
But I get this error:
Error 1 foreach statement cannot operate on variables of type
'XML__Console.gridRecord' because 'XML__Console.gridRecord' does not
contain a public definition for 'GetEnumerator'
I assume I need to inherit form and interface or something but not sure how or which one.
Grid Field Added...
class gridField : Validateit
{
public gridField()
{
Value = "---";
isValid = false;
message = "";
}
private string value;
protected bool isValid;
private string message;
public string Value
{
get { return this.value; }
set { this.value = value; }
}
public bool IsValid
{
get { return isValid; }
set { isValid = value; }
}
public string Message
{
get { return message; }
set { message = value; }
}
public override void Validate()
{
}
}
quantityField added below the other fields are much the same
class quantityField : gridField
{
public void validate()
{
if (isQuantityValid(Value) == false) { Value = "Invalid";}
}
public static bool isQuantityValid(string quantity)
{
if (quantity.Length > 3)
{
return true;
}
else
{
return false;
}
}
}
From what i understood, you want to get the name of the properties from the gridRecord class (from your example: "Quantity", "Title", "Pages")?
For that, you need to use Reflection:
var properties = typeof(gridRecord).GetProperties();
foreach (PropertyInfo propInfo in properties) {
MessageBox.Show(propInfo.Name);
}
You are attempting to iterate over one element of the collection.
foreach(gridField gf in lgr[0])
{
MessageBox.Show(gf.ToString());
}
If your goal is to retrieve the name of each property within the class, then do this.
PropertyInfo[] props = typeof(gridRecord).GetProperties();
foreach(PropertyInfo prop in props)
{
object[] attrs = prop.GetCustomAttributes(true);
foreach(object attr in attrs)
{
AuthorAttribute authAttr = attr as AuthorAttribute;
if (authAttr != null)
{
string propName = prop.Name;
string auth = authAttr.Name;
}
}
}
If you want to get name of each field you should use reflection.
PropertyInfo class should be helpful
I've a WPF application that loads a menu from an XML file, each node as a tag that identifies the user function. Each user has visibility permission that match against the tag defined in the xml file. I wish some help on simplifing that code since I's quite complex and from my point of view poor performing. Consider that the main menu is composed of main items and inside each there're specific areas function. If a user is enabled to at element at list the main menu node is shown otherwise not.
public virtual System.Threading.Tasks.Task<MenuItemNode> RegisterMenu(IDictionary<string,Type> functions)
{
var assembly = Assembly.GetCallingAssembly(); //I should get the module that invoked the base class
string filename = GetFullFileName(assembly, MenuFilename);
return Task.Factory.StartNew<MenuItemNode>(() =>
{
string xmlFileName = string.Format(filename);
var doc = new XmlDocument();
using (Stream stream = assembly.GetManifestResourceStream(xmlFileName))
{
if (stream != null)
{
using (var reader = new StreamReader(stream))
{
doc.LoadXml(reader.ReadToEnd());
}
}
}
MenuItemNode menu = BuildMenu(doc.SelectSingleNode(#"/Node"), "/", functions);
return menu;
});
}
private string GetFullFileName(Assembly assembly,string filename)
{
var resourceFiles = assembly.GetManifestResourceNames();
return resourceFiles.First(x => x.EndsWith(filename));
}
private MenuItemNode BuildMenu(XmlNode parent, string path, IDictionary<string, Type> functions)
{
Argument.IsNotNull(() => parent);
if (functions == null || (functions.Count == 0)) return null;
MenuItemNode menuItem = null;
string subPath = "Node";
string name = string.Empty;
string tag = string.Empty;
int position = 0;
bool forceVisible = false;
string parameters = string.Empty;
string group = string.Empty;
bool showInDialog = false;
if (parent.Attributes != null)
{
if (parent.Attributes["name"] != null)
name = parent.Attributes["name"].Value;
if (parent.Attributes["tag"] != null)
tag = parent.Attributes["tag"].Value;
if (parent.Attributes["position"] != null)
position = System.Convert.ToInt32(parent.Attributes["position"].Value);
if (parent.Attributes["force_visible"] != null)
forceVisible = Convert.ToBoolean(parent.Attributes["force_visible"].Value);
if (parent.Attributes["parameters"] != null)
parameters = parent.Attributes["parameters"].Value;
if (parent.Attributes["group"] != null)
group = parent.Attributes["group"].Value;
if (parent.Attributes["showindialog"] != null)
showInDialog = Convert.ToBoolean(parent.Attributes["showindialog"].Value);
}
//parent item
if (string.IsNullOrEmpty(tag))
{
menuItem = CreateMenuItem(name, position);
menuItem.ForceVisible = forceVisible;
// menuItem.Group = group;
}
else//child item
{
if (functions.ContainsKey(tag))
{
menuItem = CreateMenuItem(name, tag, position);
menuItem.ForceVisible = forceVisible;
//menuItem.GroupName = group;
menuItem.ShowInDialog = showInDialog;
//menuItem.MenuParameter = GetMenuItemParameters(parameters);
#region Multiple-tag
if ((functions == null) || !functions.Any()) return null;
#endregion
}
else
{
//todo: add-logging
}
}
if (parent.HasChildNodes)
{
foreach (XmlNode child in parent.SelectNodes(subPath))
{
MenuItemNode childMenuItem = BuildMenu(child, subPath, functions);
if (childMenuItem == null) continue;
int childPosition = childMenuItem.SortIndex;
//This to prevent out-of-boundaries exception
if (childPosition > menuItem.Children.Count)
childPosition = menuItem.Children.Count;
menuItem.Children.Insert(childPosition, childMenuItem);
}
}
return menuItem;
}
private MenuItemNode CreateMenuItem(string text, int position)
{
var item = new MenuItemNode();
item.Text = text;
item.SortIndex = position;
return item;
}
private MenuItemNode CreateMenuItem(string text, string tag, int? position)
{
MenuItemNode item = CreateMenuItem(text, (!position.HasValue) ? 0 : position.Value);
item.FunctionTag = tag;
item.SortIndex = (!position.HasValue) ? 0 : position.Value;
return item;
}
And here's the MenuItemNode class
[ContentProperty("Children")]
public class MenuItemNode : INotifyPropertyChanged
{
private string text;
private ICommand command;
private Uri imageSource;
private int sortIndex;
private bool forceVisible;
private bool showInDialog;
private bool isChecked;
public bool IsChecked
{
get
{
return this.isChecked;
}
set
{
if (this.isChecked != value)
{
this.isChecked = value;
this.RaisePropertyChanged(() => this.IsChecked);
}
}
}
public bool IsSeparator { get; set; }
public MenuItemNode()
{
Children = new MenuItemNodeCollection();
SortIndex = 50;
SetCommand();
}
public MenuItemNode(String path)
: base()
{
Path = path;
}
public MenuItemNodeCollection Children { get; private set; }
public virtual ICommand Command
{
get
{
return command;
}
set
{
if (command != value)
{
command = value;
RaisePropertyChanged(() => this.Command);
}
}
}
public Uri ImageSource
{
get
{
return imageSource;
}
set
{
if (imageSource != value)
{
imageSource = value;
RaisePropertyChanged(() => this.ImageSource);
}
}
}
public string Text
{
get
{
return text;
}
set
{
if (text != value)
{
text = value;
RaisePropertyChanged(() => this.Text);
}
}
}
private MenuGroupDescription group;
public MenuGroupDescription Group
{
get { return group; }
set
{
if (group != value)
{
group = value;
RaisePropertyChanged(() => this.Group);
}
}
}
public int SortIndex
{
get
{
return sortIndex;
}
set
{
if (sortIndex != value)
{
sortIndex = value;
RaisePropertyChanged(() => this.SortIndex);
}
}
}
public string Path
{
get;
private set;
}
public bool ForceVisible
{
get
{
return this.forceVisible;
}
set
{
if (forceVisible != value)
{
this.forceVisible = value;
RaisePropertyChanged(() => ForceVisible);
}
}
}
public bool ShowInDialog
{
get
{
return this.showInDialog;
}
set
{
if (showInDialog = value)
{
this.showInDialog = value;
RaisePropertyChanged(() => ShowInDialog);
}
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged = delegate { };
protected void RaisePropertyChanged<T>(Expression<Func<T>> propertyExpression)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyExpression.Name));
}
#endregion
protected virtual void SetCommand()
{
this.Command = FunctionMenuCommands.OpenFunctionCommand;
}
public string FunctionTag { get; set; }
}
In specific what I did is to process each child node then if visible I add it to the collection... do you see any possible better solution?
Thanks
Whoever wrote that code clearly didn't know how to write WPF. In WPF, there is a much simpler option... just use the MenuItem.Visibility property to hide (collapse) MenuItems that users don't have access to. Of course, you'd need some data bind-able security bool properties which you could then data bind to the MenuItem.Visibility property of each MenuItem via a BooleanToVisibilityConverter. Here's a simple example:
<MenuItem Header="Some option" Visibility="{Binding User.Security.HasSomeOptionPermission,
Converter={StaticResource BooleanToVisibilityConverter}}" ... />
If a particular user has the SomeOptionPermission, then the MenuItem will be displayed, otherwise it will be hidden.