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.
Related
I have a set of classes that I am using to deserialize JSON into. My program will periodically look for changes to this JSON file, and if it finds any, will push the new data to the properties of these classes using reflection.
I need to find any new items added to the collection of the Item2 class (SocialExportJSON.SocialExportData.Item2) after a successful update.
My JSON classes look like this (there are more but I want to avoid too big a wall of code):
public class Item2 : INotifyPropertyChanged
{
[JsonProperty("type")]
private string type;
public string Type
{
get
{
return type;
}
set
{
if (type != value)
{
type = value;
RaisePropertyChanged("Type");
}
}
}
[JsonProperty("id")]
private string id;
public string ID
{
get
{
return id;
}
set
{
if (id != value)
{
id = value;
RaisePropertyChanged("ID");
}
}
}
[JsonProperty("postedIso8601")]
private string postedIso8601;
public string PostedIso8601
{
get
{
return postedIso8601;
}
set
{
if (postedIso8601 != value)
{
postedIso8601 = value;
RaisePropertyChanged("PostedIso8601");
}
}
}
[JsonProperty("postedTimestamp")]
private object postedTimestamp;
public object PostedTimestamp
{
get
{
return postedTimestamp;
}
set
{
if (postedTimestamp != value)
{
postedTimestamp = value;
RaisePropertyChanged("PostedTimestamp");
}
}
}
[JsonProperty("engagement")]
private Engagement engagement;
public Engagement Engagement
{
get
{
return engagement;
}
set
{
if (engagement != value)
{
engagement = value;
RaisePropertyChanged("Engagement");
}
}
}
[JsonProperty("source")]
private Source2 source;
public Source2 Source
{
get
{
return source;
}
set
{
if (source != value)
{
source = value;
RaisePropertyChanged("Source");
}
}
}
[JsonProperty("author")]
private Author author;
public Author Author
{
get
{
return author;
}
set
{
if (author != value)
{
author = value;
RaisePropertyChanged("Author");
}
}
}
[JsonProperty("content")]
private Content content;
public Content Content
{
get
{
return content;
}
set
{
if (content != value)
{
content = value;
RaisePropertyChanged("Content");
}
}
}
[JsonProperty("location")]
private Location location;
public Location Location
{
get
{
return location;
}
set
{
if (location != value)
{
location = value;
RaisePropertyChanged("Location");
}
}
}
[JsonProperty("publication")]
private Publication publication;
public Publication Publication
{
get
{
return publication;
}
set
{
if (publication != value)
{
publication = value;
RaisePropertyChanged("Publication");
}
}
}
[JsonProperty("metadata")]
private Metadata metadata;
public Metadata Metadata
{
get
{
return metadata;
}
set
{
if (metadata != value)
{
metadata = value;
RaisePropertyChanged("Metadata");
}
}
}
//Event handling
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string property)
{
//Console.WriteLine("Updated");
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
}
public class SocialExportData : INotifyPropertyChanged
{
[JsonProperty("dataType")]
private string dataType;
public string DataType
{
get
{
return dataType;
}
set
{
if (dataType != value)
{
dataType = value;
RaisePropertyChanged("DataType");
}
}
}
[JsonProperty("id")]
private int id;
public int ID
{
get
{
return id;
}
set
{
if (id != value)
{
id = value;
RaisePropertyChanged("ID");
}
}
}
[JsonProperty("story")]
private Story story;
public Story Story
{
get
{
return story;
}
set
{
if (story != value)
{
story = value;
RaisePropertyChanged("Story");
}
}
}
[JsonProperty("order")]
private string order;
public string Order
{
get
{
return order;
}
set
{
if (order != value)
{
order = value;
RaisePropertyChanged("Order");
}
}
}
[JsonProperty("lifetime")]
private string lifetime;
public string Lifetime
{
get
{
return lifetime;
}
set
{
if (lifetime != value)
{
lifetime = value;
RaisePropertyChanged("Lifetime");
}
}
}
[JsonProperty("maxAge")]
private int maxAge;
public int MaxAge
{
get
{
return maxAge;
}
set
{
if (maxAge != value)
{
maxAge = value;
RaisePropertyChanged("MaxAge");
}
}
}
[JsonProperty("maxSize")]
private int maxSize;
public int MaxSize
{
get
{
return maxSize;
}
set
{
if (maxSize != value)
{
maxSize = value;
RaisePropertyChanged("MaxSize");
}
}
}
[JsonProperty("consumeCount")]
private int consumeCount;
public int ConsumeCount
{
get
{
return consumeCount;
}
set
{
if (consumeCount != value)
{
consumeCount = value;
RaisePropertyChanged("ConsumeCount");
}
}
}
[JsonProperty("consumeInterval")]
private int consumeInterval;
public int ConsumeInterval
{
get
{
return consumeInterval;
}
set
{
if (consumeInterval != value)
{
consumeInterval = value;
RaisePropertyChanged("ConsumeInterval");
}
}
}
[JsonProperty("items")]
private ObservableCollection<Item2> items;
public ObservableCollection<Item2> Items
{
get
{
return items;
}
set
{
if (items != value)
{
items = value;
RaisePropertyChanged("Items");
}
}
}
//Event handling
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string property)
{
//Console.WriteLine("Updated");
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
}
public class SocialExportJSON : INotifyPropertyChanged
{
[JsonProperty("id")]
private string id;
public string ID
{
get
{
return id;
}
set
{
if (id != value)
{
id = value;
RaisePropertyChanged("ID");
}
}
}
[JsonProperty("ttl")]
private int ttl;
public int TTL
{
get
{
return ttl;
}
set
{
if (ttl != value)
{
ttl = value;
RaisePropertyChanged("TTL");
}
}
}
[JsonProperty("serial")]
private long serial;
public long Serial
{
get
{
return serial;
}
set
{
if (serial != value)
{
serial = value;
RaisePropertyChanged("Serial");
}
}
}
[JsonProperty("formatType")]
private string formatType;
public string FormatType
{
get
{
return formatType;
}
set
{
if (formatType != value)
{
formatType = value;
RaisePropertyChanged("FormatType");
}
}
}
[JsonProperty("modifiedIso8601")]
private string modifiedIso8601;
public string ModifiedIso8601
{
get
{
return modifiedIso8601;
}
set
{
if (modifiedIso8601 != value)
{
modifiedIso8601 = value;
RaisePropertyChanged("ModifiedIso8601");
}
}
}
[JsonProperty("modifiedTimestamp")]
private long modifiedTimestamp;
public long ModifiedTimestamp
{
get
{
return modifiedTimestamp;
}
set
{
if (modifiedTimestamp != value)
{
modifiedTimestamp = value;
RaisePropertyChanged("ModifiedTimestamp");
}
}
}
[JsonProperty("timezone")]
private string timezone;
public string Timezone
{
get
{
return timezone;
}
set
{
if (timezone != value)
{
timezone = value;
RaisePropertyChanged("Timezone");
}
}
}
[JsonProperty("dataType")]
private string dataType;
public string DataType
{
get
{
return dataType;
}
set
{
if (dataType != value)
{
dataType = value;
RaisePropertyChanged("DataType");
}
}
}
[JsonProperty("exports")]
private ObservableCollection<SocialExportData> exports;
public ObservableCollection<SocialExportData> Exports
{
get
{
return exports;
}
set
{
if (exports != value)
{
exports = value;
RaisePropertyChanged("Exports");
}
}
}
//Event handling
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string property)
{
//Console.WriteLine("Updated");
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
}
In another class, I have a method to deserialize to a global instance of my JSON class. It looks like this:
public SocialExportJSON socialExportData;
private async void DownloadAndDeserializeJSONAsync()
{
try
{
//Create a web client with the supplied credentials
var exportClient = new WebClient { Credentials = new NetworkCredential(uName, pw), Encoding = Encoding.UTF8};
//Create a task to download the JSON string and wait for it to finish
var downloadTask = Task.Run(() => exportClient.DownloadString(new Uri(eURL)));
downloadTask.Wait();
//Get the string from the task
var JSONString = await downloadTask;
//Create a task to deserialize the JSON from the last task
var DeserializeTask = Task.Run(() => JsonConvert.DeserializeObject<SocialExportJSON>(JSONString));
DeserializeTask.Wait();
SocialExportJSON sej = await DeserializeTask;
//Check the timestamp first to see if we should change the data
if(socialExportData == null)
{
//Get the data from the task
socialExportData = await DeserializeTask;
}
else if(sej.ModifiedTimestamp != socialExportData.ModifiedTimestamp)
{
//Get the data from the task
SocialExportJSON newData = await DeserializeTask;
GetNewItems(newData);
SetNewData(newData);
//Call the exportUpdated event when the task has finished
exportUpdated();
}
}
catch (Exception e)
{
MessageBox.Show(e.Message.ToString());
}
}
In my SetNewData function, shown below, I use reflection to set the properties of my global class. Because I'm setting the whole collection rather than iterating through each of the properties in each of the classes, I can't use the CollectionChanged event to find new items.
public void SetNewData(SocialExportJSON newData)
{
//Loop through each of the properties and copy from source to target
foreach (PropertyInfo pi in socialExportData.GetType().GetProperties())
{
if (pi.CanWrite)
{
pi.SetValue(socialExportData, pi.GetValue(newData, null), null);
}
}
}
Is there a way I can modify my SetNewData function in such a way that it calls CollectionChanged? If not, what would be the best way to go about getting any new additions to my collection of Item2?
In my Main function. I create an instance of my class called SocialExport like so:
SocialExport s = new SocialExport("http://example.json", "example", "example");.
This class is where the global instance of my JSON class is contained, and my event handler is added like so
s.socialExportData.Exports[0].Items.CollectionChanged += CollectionChanged;
Then you are hooking up an event handler for the CollectionChanged event for that particular instance of ObservableCollection<Item2>.
If you create a new ObservableCollection<Item2>, you obviously must hook up an event handler to this one as well. The event handler that is associated with the old object won't be invoked when new items are added to the new instance.
So whenever a new ObservableCollection<Item2> is created, using deserialization or not, you should hook up a new event handler.
You could probably do this in your DownloadAndDeserializeJSONAsync method. The other option would be to create only one instance of the collection and remove and add items from/to this one.
I'm a student in a C# class and this is my introductory assignment to Classes, so please bear with me. When the New button is pressed, a CPerson object will be created using the name and phone values and the object will be added to a List<>.
class CPerson
{
private string m_sName;
private string m_sPhone;
public string Name
{
get { return this.m_sName; }
set
{
this.m_sName = value;
}
}
public string Phone
{
get { return this.m_sPhone; }
set
{
this.m_sPhone = value;
}
}
}
public partial class Form1 : Form
{
private List<CPerson> PhoneNum = new List<CPerson>(); //<CPerson> or <string>?
public Form1()
{
InitializeComponent();
newbutton.Enabled = false;
changebutton.Enabled = false;
savebutton.Enabled = false;
}
private void newbutton_Click(object sender, EventArgs e)
{
changebutton.Enabled = true;
savebutton.Enabled = true;
PhoneNum.Add(new CPerson { Name = Namebox.Text + " : ", Phone = phonebox.Text });
listBox1.Items.Add(PhoneNum); //text = "Collection"
}
The assignment says "The CPerson ToString() override will be used to display the name and phone number in the listbox" as shown in the above image, which I don't necessarily understand, but I'm guessing I have to use something like this?
CPerson data = new CPerson();
data.ToString();
Either way, as the code is now, all I get in my listbox is "(Collection)". Any help would be appreciated!
That is asking to override the ToString() method. You can do it like this:
class CPerson
{
private string m_sName;
private string m_sPhone;
public string Name
{
get { return this.m_sName; }
set
{
this.m_sName = value;
}
}
public string Phone
{
get { return this.m_sPhone; }
set
{
this.m_sPhone = value;
}
}
public override string ToString()
{
return Name + ": " + Phone;
}
I did not get right the part of adding to the list, but I assume you can do the following using ToString():
listBox1.Items.Add(data.ToString());
Close...
class CPerson
{
private string m_sName;
private string m_sPhone;
public string Name
{
get { return this.m_sName; }
set
{
this.m_sName = value;
}
}
public string Phone
{
get { return this.m_sPhone; }
set
{
this.m_sPhone = value;
}
}
public override string ToString()
{
return Name + ": " + Phone;
}
}
}
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 :)
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.
I am trying to reach a foreach but my program never gets inside because my ICollection Coletores is always empty even if I put a lot of stuff in there.
The code where I want to get inside and it is always empty (I want to get inside the second foreach):
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
if (NavigationContext.QueryString.TryGetValue("email", out email))
{
//MessageBox.Show(email);
List<HyperlinkButton> listaLinks = new List<HyperlinkButton>();
AppDataContext db = new AppDataContext();
int i = 0;
HyperlinkButton aux = new HyperlinkButton();
foreach (Pessoa pessoa in db.Pessoas)
{
if (pessoa.Email == email)
{
foreach (Coletor coletor in pessoa.Coletores)
{
aux.Content = "Coletor " + (i + 1).ToString();
aux.FontSize = 24;
aux.NavigateUri = new Uri("/OcorrenciasPage.xaml?coletorId=" + coletor.Id.ToString(), UriKind.RelativeOrAbsolute);
listaLinks.Add(aux);
i++;
}
}
}
ListBox coletores = new ListBox();
coletores.ItemsSource = listaLinks;
stcList.Children.Add(coletores);
}
base.OnNavigatedTo(e);
}
Now the code that I am adding data:
if (txtLat.Text != "" && txtLong.Text != "" && rdNorte.IsChecked == true || rdSul.IsChecked == true && rdLeste.IsChecked == true || rdOeste.IsChecked == true)
{
foreach (var pessoa in db.Pessoas)
{
if (pessoa.Email == email)
{
pessoa.Coletores.Add(coletor);
}
}
db.Coletores.InsertOnSubmit(coletor);
db.SubmitChanges();
NavigationService.Navigate(new Uri("/ColetoresPage.xaml?email=" + email, UriKind.RelativeOrAbsolute));
}
Now, my Pessoa class:
public class Pessoa : INotifyPropertyChanged
{
private int _id;
[Column(IsDbGenerated = true, IsPrimaryKey = true)]
public int Id {
get { return _id;}
set { _id = value;
OnPropertyChanged("Id");
}
}
private string _nome;
[Column]
public string Nome
{
get { return _nome; }
set { _nome = value;
OnPropertyChanged("Nome");
}
}
private string _email;
[Column]
public string Email
{
get { return _email; }
set { _email = value;
OnPropertyChanged("Email");
}
}
private string _senha;
[Column]
public string Senha { get { return _senha; }
set { _senha = value;
OnPropertyChanged("Senha");
}
}
private string _profissao;
[Column]
public string Profissao { get { return _profissao; }
set { _profissao = value;
OnPropertyChanged("Profissao");
}
}
private int _idade;
[Column]
public int Idade { get { return _idade; }
set { _idade = value;
OnPropertyChanged("Idade");
}
}
private string _endereco;
[Column]
public string Endereco { get { return _endereco; }
set { _endereco = value;
OnPropertyChanged("Endereco");
}
}
private string _cidade;
[Column]
public string Cidade { get { return _cidade; }
set { _cidade = value;
OnPropertyChanged("Cidade");
}
}
private string _estado;
[Column]
public string Estado { get { return _estado; }
set { _estado = value;
OnPropertyChanged("Estado");
}
}
private EntitySet<Coletor> _coletores = new EntitySet<Coletor>();
[Association(Name = "FK_Coletores_PessoaColetores", Storage = "_coletores", ThisKey = "Id", OtherKey = "pessoaId")]
public ICollection<Coletor> Coletores
{
get { return _coletores; }
set { _coletores.Assign(value); }
}
private EntitySet<PessoaColetor> _pessoaColetores = new EntitySet<PessoaColetor>();
[Association(Name = "FK_PessoaColetores_Pessoas", Storage = "_pessoaColetores", OtherKey = "pessoaId", ThisKey = "Id")]
private ICollection<PessoaColetor> PessoaColetores
{
get { return _pessoaColetores; }
set { _pessoaColetores.Assign(value); }
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
}
The Coletores property on the Pessoa class looks alright. There is also a PessoaColetores property. Are you sure there has been no confusion between the two? Especially with intellisense one might dot or tab the wrong one.
Have you put a break point on the line that actually adds coletors (second code snippet)? Maybe stuff is added to the wrong collection.
Cheers, B.