In a Winforms application, I have this code:
private void BtnNuevoGrupo_Click(object sender, EventArgs e)
{
TreeNode newNode = TreDevices.Nodes[0].Nodes.Add("Nuevo grupo de validaciĆ³n");
TreDevices.Nodes[0].Expand();
TreDevices.SelectedNode = newNode;
newNode.Tag = "IN:0";
newNode.BeginEdit();
}
With that code, I am adding a tree node and starting edit immediately. Then, I have this code:
private async void TreDevices_AfterLabelEdit(object sender, NodeLabelEditEventArgs e)
{
e.Node.ContextMenuStrip = new ContextMenuStrip();
var itemEntrada = e.Node.ContextMenuStrip.Items.Add("Entrada");
itemEntrada.Click += InOutItem_Click;
}
Finally, I have this code to do some action when the context menu item is clicked:
private async void InOutItem_Click(object? sender, EventArgs e)
{
if (sender is not null)
{
var item = (ToolStripMenuItem)sender;
ContextMenuStrip menu = (ContextMenuStrip)item.Owner;
// HERE I NEED TO GET A REFERENCE TO THE TreeNode
}
}
In InOutItem_Click I need to get a reference to the TreeNode that owns the menu. How can I do it?
I can only get a reference to the tree control by using item.Owner.SourceControl.
Have you considered just using the Tag property of itemEntrada?
private void TreDevices_AfterLabelEdit(object sender, NodeLabelEditEventArgs e)
{
e.Node.ContextMenuStrip = new ContextMenuStrip();
var itemEntrada = new ToolStripMenuItem
{
Text = "Entrada",
Tag = e.Node,
};
e.Node.ContextMenuStrip.Items.Add(itemEntrada);
itemEntrada.Click += InOutItem_Click;
}
private void InOutItem_Click(object sender, EventArgs e)
{
if ((sender is ToolStripMenuItem tsmi) && (tsmi.Tag is TreeNode node))
{
var item = (ToolStripMenuItem)sender;
ContextMenuStrip menu = (ContextMenuStrip)item.Owner;
MessageBox.Show($"Clicked {node.Text}");
}
}
Related
I have a problem I've ran into and I'm not sure if it is possible to prevent it. I supose it is designed like this by default.
I have coded a treeview list to be filled by a XML and each of these node, when selected, are filling some textbox. Depending on their type, it will trigger a different function.
The problem is that when I select a child, it seems to trigger "IsSelecting" for all parents treeviewitem all the way to the top which in return trigger the associated function as well and I don't want that.
Any idea how to prevent this "Sort of reverse inheritance" for IsSelected?
Example (check with code below): selecting a "node" will trigger "Node_Selected", "Dialog_Selected", "Actor_Selected".
Thanks for your help.
Best regards,
Just for context:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
XmlDocument document = new XmlDocument();
document.Load("XML/ActorsDialogs.xml");
XmlNodeList actors = document.SelectNodes("/dialogs/actor");
foreach (XmlNode actor in actors)
{
TreeViewItem newActor = new TreeViewItem();
newActor.Header = actor.SelectSingleNode("actorname").InnerText;
newActor.Selected += new RoutedEventHandler(Actor_Selected);
XmlNodeList dialogs = actor.SelectNodes("dialog");
foreach (XmlNode dialog in dialogs)
{
TreeViewItem newdialog = new TreeViewItem();
newdialog.Header = "Dialog:" + dialog.SelectSingleNode("dialogID").InnerText;
newdialog.Selected += new RoutedEventHandler(Dialog_Selected);
BuildNodes(newdialog, dialog);
newActor.Items.Add(newdialog);
}
ActorsList.Items.Add(newActor);
}
}
private void BuildNodes(TreeViewItem treeNode, XmlNode parentElement)
{
foreach (XmlNode child in parentElement.ChildNodes)
{
if (child.Name == "node" || child.Name == "reply")
{
XmlElement childElement = child as XmlElement;
TreeViewItem childTreeNode = new TreeViewItem();
string ID = child.SelectSingleNode(child.Name + "ID").InnerText;
childTreeNode.Header = childElement.Name + ":" + ID;
switch (child.Name)
{
case "node":
childTreeNode.Selected += new RoutedEventHandler(Node_Selected);
break;
case "reply":
childTreeNode.Selected += new RoutedEventHandler(Reply_Selected);
break;
default:
break;
}
treeNode.Items.Add(childTreeNode);
BuildNodes(childTreeNode, childElement);
}
}
}
private void Actor_Selected(object sender, RoutedEventArgs e){}
private void Dialog_Selected(object sender, RoutedEventArgs e){}
private void Node_Selected(object sender, RoutedEventArgs e){}
private void Reply_Selected(object sender, RoutedEventArgs e){}
In the event handler you can set e.Handled = true. That will prevent the event from bubbling up the tree.
private void Node_Selected(object sender, RoutedEventArgs e)
{
e.Handled = true; //this will prevent the event from bubbling up to parents;
//Do the rest of the code here.
}
See https://msdn.microsoft.com/en-us/library/ms742806%28v=vs.110%29.aspx for more information on RoutedEvents. These include bubbling events which go up the tree and tunneling events which go down the tree.
how to enable menu strip in child form?
i just want to enable the menu button strip when i will close the child form
how to code that in child form?
Student....
private void tsmNewEmp_Click(object sender, EventArgs e)
{
if(NewEmp == null)
{
NewEmp = new NewEmployee();
NewEmp.MdiParent = this;
}
NewEmp.Show();
tsmNewEmp.Enabled = false;
tsmNewContract.Enabled = false;
}
You can use the FormClosed event to update the buttons in the parent form after the child is closed:
private void tsmNewEmp_Click(object sender, EventArgs e)
{
if(NewEmp == null)
{
NewEmp = new NewEmployee();
NewEmp.MdiParent = this;
NewEmp.FormClosed += FormClosed_1;
}
NewEmp.Show();
tsmNewEmp.Enabled = false;
tsmNewContract.Enabled = false;
}
private void FormClosed_1(object sender, FormClosedEventArgs e)
{
tsmNewEmp.Enabled = true;
tsmNewContract.Enabled = true;
}
Control[] controls = this.MdiParent.Controls.Find("Menu", true);
foreach (Control ctrl in controls)
{
if (ctrl.Name == "Menu")
{
MenuStrip strip = ctrl as MenuStrip;
strip.Items["login"].Enabled = false;
strip.Items["logout"].Enabled = false;
}
}
First, I have filled a list object with the data from xml file. After that, I have filled a ListView with the necessary fields, without any problem. How can I get the index from the selected ListView item and then give appropriate value to some textbox?
This is the code for it:
private void Form1_Load(object sender, EventArgs e)
{
List<Tasks> taskList = new List<Tasks>();
listView1.Columns.Add("Date:");
listView1.Columns.Add("Job:");
listView1.Columns.Add("Client Name");
listView1.Columns.Add("Submitted by");
taskList = getTasks();
listView1.Items.Clear();
for (int i = 0; i < taskList.Count; i++)
{
Tasks task = taskList.ElementAt(i);
ListViewItem row = new ListViewItem();
row.Text=task.date.ToString();
row.SubItems.Add(task.job);
row.SubItems.Add(task.clientName);
row.SubItems.Add(task.submittedBy);
listView1.Items.Add(row);
}
}
public List<Tasks> getTasks()
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("data.xml");
XmlNodeList nodes = xmlDoc.DocumentElement.SelectNodes("/tasks/task");
List<Tasks> taskList = new List<Tasks>();
foreach (XmlNode node in nodes)
{
Tasks task = new Tasks();
task.id = Convert.ToInt32(node.SelectSingleNode("id").InnerText);
task.date = Convert.ToDateTime(node.SelectSingleNode("submittedDate").InnerText);
task.submittedBy = node.SelectSingleNode("submittedBy").InnerText;
task.clientName = node.SelectSingleNode("clientName").InnerText;
task.job = node.SelectSingleNode("job").InnerText;
task.taskCategory = node.SelectSingleNode("taskCategory").InnerText;
task.taskDescription = node.SelectSingleNode("taskDescription").InnerText;
task.hours = node.SelectSingleNode("hours").InnerText;
task.status = node.SelectSingleNode("status").InnerText;
task.isBilled = node.SelectSingleNode("isBilled").InnerText;
task.cost = node.SelectSingleNode("cost").InnerText;
task.followUpInfo = node.SelectSingleNode("followUpInfo").InnerText;
task.invoiceNumber = node.SelectSingleNode("quickBooksInvoiceNo").InnerText;
taskList.Add(task);
}
return taskList;
}
private void listView1_SelectedIndexChanged(object sender, EventArgs e)
{
}
What I need is now how when I click an item from the listView1 to show some value in a textbox? But that value should be taken from the list object taskList, not from the xml document itself.
Store your task ID inside of your item's Tag property:
row.Tag = task.id;
Then handle ListView.SelectedIndexChanged event
private void listView1_SelectedIndexChanged(object sender, EventArgs e)
{
if (listView1.SelectedItems.Count > 0)
{
var id = (int) listView1.SelectedItems[0].Tag;
var currenTask = taskList.Where(t => t.id == id).First();
textBox1.Text = currenTask.taskDescription; // for example
}
}
Also you should define your taskList in the class level, outside of your Form_Load method.Otherwise you can't access it from SelectedIndexChanged event.
List<Tasks> taskList = new List<Tasks>();
private void Form1_Load(object sender, EventArgs e)
{
...
}
I have 12 buttons in my Form1, and each button has a textbox next to it. The button event calls a method called dialogueOpen which handles getting the an object from form2 and placing a string value in a textbox.
How can I place the value returned in a textbox depending on what button the user clicked on? So if it is button1 a user clicked on, then the text returned should be placed in textbox1 and if it is button2 the user clicked on then the text returned should be placed in textbox2. The point is avoid using a string name to check as the buttons can all be called "browse".
Right now my code below does that but it is quite repetitive is there is a better of doing this?
private void dailogueOpen(String btnName)
{
if (listBox1.SelectedItem == null)
{
MessageBox.Show("Please Select a form");
}
else
{
var selectedItem = (FormItems)listBox1.SelectedItem;
var form2result = new Form2(myDataSet, selectedItem);
var resulOfForm2 = form2result.ShowDialog();
if (resulOfForm2 == DialogResult.OK)
{
switch (btnName)
{
case "btn1":
textBox1.Text = form2result.getValue();
break;
case "btn2":
textBox2.Text = form2result.getValue();
break;
case "btn3":
textBox3.Text = form2result.getValue();
break;
case "btn4":
textBox4.Text = form2result.getValue();
break;
case "btn5":
textBox5.Text = form2result.getValue();
break;
}
}
}
}
private void button1_Click(object sender, EventArgs e)
{
String name = "btn1";
dailogueOpen(name);
}
private void button2_Click(object sender, EventArgs e)
{
String name = "btn2";
dailogueOpen(name);
}
private void button3_Click(object sender, EventArgs e)
{
String name = "btn3";
dailogueOpen(name);
}
private void button4_Click(object sender, EventArgs e)
{
String name = "btn4";
dailogueOpen(name);
}
private void button5_Click(object sender, EventArgs e)
{
String name = "btn5";
dailogueOpen(name);
}
EDIT: I just noticed your event handlers. More refactoring ensues:
Yes, there is. You need to somehow associate textboxes to buttons. For example, create a dictionary like so:
Dictionary<Button, TextBox> _dict;
_dict[button1] = textBox1;
_dict[button2] = textBox2;
...
Use one event handler for all events:
private void button_click(object sender, EventArgs e)
{
dialogeOpen((Button)sender);
}
Change dialogueOpen to accept a Button instead of a string and
_dict[btn].Text = form2Result.getValue();
replace your eventhandlers to
private void ButtonClick(object sender, EventArgs e)
{
var button = sender as Button;
if (button == null) return;
String name = button.Text;// Tag, name etc
dailogueOpen(name);
}
1 You use the same delegate on all button
Nota (Thank's to Marty) : When You're in the Form Designer, select all buttons, and then assing then "Generic_Click" for all of them, or you can use code below.
this.btn1.Click += new System.EventHandler(Generic_Click); //the same delegate
this.btn2.Click += new System.EventHandler(Generic_Click);
this.btn3.Click += new System.EventHandler(Generic_Click);
....
private void Generic_Click(object sender, EventArgs e)
{
var control = (Button)sender;
if( control.Name == "btn1")
{
....
}
else if( control.Name == "btn2")
{
....
}
else if( control.Name == "btn3")
{
....
}
}
I would first use just one event handler for the buttons, it would look like this:
protected void ButtonClick(object sender, EventArgs e)
{
Button clickedButton = (Button) sender;
string selectedId = clickedButton.ID;
string[] idParameters = selectedId.Split('_');
string textBoxId = "textbox" + idParameters[1];
dailogueOpen(textBoxId);
}
What I did here is use a pattern for the names of the textboxes, so for instance if you have buttons with ids like: button_1 ,button_2, ..., button_n, you can infer what the corresponding textbox is.
If you click button_1, by spliting its id you'll know that its corresponding textbox is the one whose id is textbox1.
Then the dialogueOpen function would look like this:
private void dailogueOpen(string textBoxId)
{
if (listBox1.SelectedItem == null)
{
MessageBox.Show("Please Select a form");
}
else
{
var selectedItem = (FormItems)listBox1.SelectedItem;
var form2result = new Form2(myDataSet, selectedItem);
var resulOfForm2 = form2result.ShowDialog();
if (resulOfForm2 == DialogResult.OK)
{
TextBox textBox = (TextBox)this.Form.FindControl("MainContent").FindControl(textBoxId);
textBox.Text = resulOfForm2.getValue();
}
}
Where MainContent is the id of container where the textboxes are.
All in all:
I would use a pattern for button and texboxes id.
According to the button being clicked I infer its corresponding texbox id.
Then find the texbox and update its value.
You can have dictionary and one event method on all button clicks
Dictionary<Button, TextBox> dx = new Dictionary<Button, TextBox>;
private void ButtonClick(object sender, EventArgs e)
{
var button = sender as Button;
if (button == null) return;
dx[button].Text = form2result.getValue();
}
and constructor like this:
public ClassName()
{
dx.Add(button1, textBox1);
dx.Add(button2, textBox2);
dx.Add(button3, textBox3);
}
I think the first thing you can do is improve readability by removing the need for the switch statement:
private void dailogueOpen(TextBox textBox)
{
if (listBox1.SelectedItem == null)
{
MessageBox.Show("Please Select a form");
}
else
{
var selectedItem = (FormItems)listBox1.SelectedItem;
var form2result = new Form2(myDataSet, selectedItem);
var resulOfForm2 = form2result.ShowDialog();
if (resulOfForm2 == DialogResult.OK)
{
textBox.Text = form2result.getValue();
}
}
}
private void button1_Click(object sender, EventArgs e)
{
dailogueOpen(textBox1);
}
private void button2_Click(object sender, EventArgs e)
{
dailogueOpen(textBox2);
}
private void button3_Click(object sender, EventArgs e)
{
dailogueOpen(textBox3);
}
private void button4_Click(object sender, EventArgs e)
{
dailogueOpen(textBox4);
}
private void button5_Click(object sender, EventArgs e)
{
dailogueOpen(textBox5);
}
This then gives you a reasonable method signature to introduce the dictionary (suggested by two other people) to map Button to TextBox, which would in turn allow you to use a single event handler (suggested by two other people) for all buttons.
private void button_Click(object sender, EventArgs e)
{
Button button = sender as Button;
if (button == null) return;
String name = button.Text;// Tag, name etc
dailogueOpen(name);
}
private void dailogueOpen(String btnName)
{
if (listBox1.SelectedItem == null)
{
MessageBox.Show("Please Select a form");
}
else
{
var selectedItem = (FormItems)listBox1.SelectedItem;
var form2result = new Form2(myDataSet, selectedItem);
var resulOfForm2 = form2result.ShowDialog();
if (resulOfForm2 == DialogResult.OK)
{
SetTxt(btnName,form2result.getValue());
}
}
}
private void SetTxt(string btnName, string value)
{
int lenght = "Button".Length;
string index = btnName.Substring(lenght); //remove Button
TextBox t = (TextBox)this.Controls.Find("textBox" + index, true)[0];
if (t != null)
t.Text = value;
}
I have a small file explorer application [WINFORMS], and i use ListView Control to explore items.
So the listView display the files and the folders from the current address [From local Computer].
i need to enable drag&drop functionality to let a File/Folder easy to move/copy to another Folder in the same Address.
each item has some preperties:
(item.Text/item.Name) has the file/folder Name.
item.ToolTipText has the file/folder Path.
item.SubItems[ 1 ].Text for a file it will respresent the file size like "13.45 MB" and for a folder, it's going to be string.Empty [However, there's several way to know whether its a file or a folder].
I've seen many tutorials about how to use drag&drop in listview, but it was like from Windows File Explorer to ListView, or from a ListView to another one, but in my case i need to know how to drag&drop in the same ListView.
I've Enabled AllowDrop property of the ListView. and also Activated the following functions:
private void listView1_DragDrop(object sender, DragEventArgs e)
{
}
private void listView1_DragEnter(object sender, DragEventArgs e)
{
}
private void listView1_ItemDrag(object sender, ItemDragEventArgs e)
{
}
UPDATE:
i tried to use this :
private void listView1_DragDrop(object sender, DragEventArgs e)
{
ListViewItem item = (ListViewItem)e.Data.GetData(typeof(ListViewItem)); //this should be the target item (FOLDER)
StringBuilder s = new StringBuilder();
foreach (ListViewItem i in listView1.SelectedItems)
{
s.AppendLine(i.Text);
}
MessageBox.Show("DRAGGED ITEM : " + s.ToString() + "TARGET ITEM : " + item.Text);
}
private void listView1_DragEnter(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Copy;
}
private void listView1_MouseDown(object sender, MouseEventArgs e)
{
var item = listView1.GetItemAt(e.X, e.Y);
if (item != null)
{
listView1.DoDragDrop(item, DragDropEffects.Copy);
}
}
at listView1_MouseDown i get the item which mouse points onto, but it gives me the item before i drop the dragged item, so if i am dragging a folder named "SWImg" to the folder "ODDFiles" , the messageBox shows "SWImg - SWImg"
then i replaced listView1_MouseDown with listView1_ItemDrag :
private void listView1_ItemDrag(object sender, ItemDragEventArgs e)
{
if (e.Item != null)
{
listView1.DoDragDrop(e.Item, DragDropEffects.Copy);
}
}
same result :S.
I've figured it out.
private void listView1_DragDrop(object sender, DragEventArgs e)
{
if (listView1.SelectedItems.Count == 0) { return; }
Point p = listView1.PointToClient(MousePosition);
ListViewItem item = listView1.GetItemAt(p.X, p.Y);
if (item == null) { return; }
List<ListViewItem> collection = new List<ListViewItem>();
foreach (ListViewItem i in listView1.SelectedItems)
{
collection.Add((ListViewItem)i.Clone());
}
if ((e.Effect & DragDropEffects.Move) == DragDropEffects.Move)
{
Thread thMove = new Thread(unused => PasteFromMove(item.ToolTipText, collection));
thMove.Start();
}
else
{
Thread thCopy = new Thread(unused => PasteFromCopy(item.ToolTipText, collection));
thCopy.Start();
}
}
private void listView1_DragOver(object sender, DragEventArgs e)
{
if ((e.KeyState & 8) == 8)
e.Effect = DragDropEffects.Copy;
else
e.Effect = DragDropEffects.Move;
}
private void listView1_ItemDrag(object sender, ItemDragEventArgs e)
{
listView1.DoDragDrop(e.Item,DragDropEffects.All);
}