How to differentiate two instances of same form control in .net - c#

I have 2 Treeview in one form as below.
left_treeview_node1 | right_treeview_node1
left_treeview_node2 | right_treeview_node2
left_treeview_node3 | right_treeview_node3
left_treeview_node4 | right_treeview_node4
here we can drag and drop left treenode on right for mapping.
now user has opened 2 instances of same form and he is dragging left_treeview_node1 from first instance and dropping it to right_treeview_node4 of another instance of same form.
so how to differentiate the another instance and stop supporting drag and drop from one instance to another instance.
are there different GUID for each instance of same form?
can we use Mutex to differentiate between 2 instances of same form?
Thanks in advance...

I'll assume you pass the TreeNode as the object to drag:
private void treeView1_ItemDrag(object sender, ItemDragEventArgs e) {
treeView1.DoDragDrop(e.Item, DragDropEffects.Move);
}
Then you want to write the DragEnter event handler on the second TreeView to verify that you indeed get a TreeNode and that it came from the TreeView you expected:
private void treeView2_DragEnter(object sender, DragEventArgs e) {
if (!e.Data.GetDataPresent(typeof(TreeNode))) return;
var node = (TreeNode)e.Data.GetData(typeof(TreeNode));
if (node.TreeView == this.treeView1) {
e.Effect = DragDropEffects.Move;
}
}
The object identity check will not match it the node came from another form. If you want to check that it came from the expected form instead of the expected TreeView (seems unlikely here) then write the test as if (node.TreeView.FindForm() == this).

Use Control.Handle property which uniquely identifies a control or a form in your case.

Compare values returned by Control.FindForm - do not allow dropping if they are different for a dragged and target items.

You can also just test in the drag events to see if the form is focused. If it's not then you know the rest. Or if you really want to be sure, disable/enable drag drop on the controls when the form loses/gains focus.

Here I have used the control's HASHCODE to determine the different instance of the control like below and it worked.
in tvw1.DragDrop event
Dim draggedNode As TreeNode = Nothing
draggedNode = DirectCast(e.Data.GetData(GetType(TreeNode)), TreeNode)
If draggedNode Is Nothing Then Exit Sub
If Not (draggedNode.TreeView.GetHashCode = tvwStagingArea.GetHashCode) Then
'do whatever you want
Exit Sub
End If

Related

Nested DataGridView Control

I am trying to create a nested DataGridView control where there will be two levels of nesting that are open at all times. It will look similar to the picture on this page: http://www.codeproject.com/Articles/12657/GridView-inline-Master-Detail-record-display. The difference will be that each subnesting will always be open and it is not necessary to have a way for the user to open/close each nesting. This control will only be used for displaying data, so there will be no need to modify the data directly from this control (even though the user will not modify the data directly it can still be changed).
If this can not be done with DataGridView, is there any other control that would allow for this.
If not does anyone know another way to do this. I can, but they would be tedious to implement. One way would be to add multiple DataGridView controls in sequence (2N DataGridControls for N categories). The other would add it all manually with static controls.
I don't know if this will give the answer, but it might make u some door.
//button to call function that looks for DatagridView control
private void button2_Click(object sender, EventArgs e)
{
scanDG(this);
}
private void scanDG(Control parent)
{
foreach (Control ctrl in parent.Controls)
{
if (ctrl.GetType().Name == "DataGridView")
{//If current Control is Datagridview then set Readonly to true
((DataGridView)ctrl).ReadOnly = true;
}
//If a control can contain control scan it and look for Datagridview control
if (ctrl.HasChildren) scanDG(ctrl);
}
}

Updating Form1's widgets by clicking Form2's button in Visual C# Windows Forms

I'm fairly new to Visual C# and I'm writing an GUI app with multiple forms. One form is main window, and the rest are some kind of option windows. When showing an option window, I need to load some data to it (for example a string to window's editbox), then edit it and return back to main window when closing option window. Is there any simple way I can achieve it?
I've found some solutions like, or c# event handling between two forms, but I can't really conform it to my needs. I was thinking about passing data in constructor, but how to get it back? I've found something about ShowDialog, but as I said I'm new to C# (started yesterday ^^) and don't know if I can use it.
Any ideas, please?
I found the following previous answer which outlines sending specific properties from the one form to another:
Send values from one form to another form
The using keyword will also ensure that the form is cleaned-up properly, here's a link to it's usage (pardon the pun...) : http://msdn.microsoft.com/en-us/library/vstudio/yh598w02.aspx
I've run into the same issue to be honest, and I have to say that prior to this discussion I would just pass the parent form itself to the child and alter it in that way. Such as:
ChildForm child = new ChildForm(this); //from the parent
and
public ChildForm(ParentForm parent)
{
this.parent = parent;
}
Probably not the best convention though, as you probably don't need to access that much from the parent as the child.
Thanks guys, I think I finally get it. Idle_Mind, your idea was the easiest in my point of view, so I decided to use it. If someone else has a problem like this, here's what I've coded:
In main window form: when button is clicked, a new form appears; after closing it, label1 shows the text typed in that form
private void Button1_Click(object sender, EventArgs e)
{
LoadDataForm loaddata = new LoadDataForm("initial value");
if (loaddata.ShowDialog() == DialogResult.OK)
{
label1.Text = loaddata.textBox1.Text;
}
}
In load data form: argument passed in form's constructor appears in textBox1; textBox1's Modifiers property has to be modified to "public"
public LoadDataForm(string initvalue)
{
InitializeComponent();
textBox1.Text = initvalue;
}
private void ApplyButton_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.OK;
}
Regards,
mopsiok

A way to monitor when a Control's screen location changes?

With WinForms, is there a way to be alerted to a control changing location with respect to the screen?
Say you have a Form with a button on it, and you would like to know when the button is moved from its current pixel location on the screen. If the button is moved to a different location on its parent Form you could obviously use the LocationChanged event, but if the Form is moved by the user, how do you know the button has visually moved?
In this simplified case the quick answer is to monitor the Form's LocationChanged and SizeChanged events, but there can be an arbitrary number of levels of nesting so monitoring those events for each parent up the chain to the primary form is not feasible. Using a timer to check if the location changed also seems like cheating (in a bad way).
Short version:
Given only an arbitrary Control object, is there a way to know when that Control's location changes on the screen, without knowledge of the control's parent hierarchy?
An illustration, by request:
Note that this "pinning" concept is an existing capability but it currently requires knowledge of the parent form and how the child control behaves; this is not the problem I am trying to solve. I would like to encapsulate this control tracking logic in an abstract Form that "pin-able" Forms can inherit from. Is there some message pump magic I can tap into to know when a control moves on the screen without having to deal with all the complicated parent tracking?
I'm not sure why you would say tracking the parent chain "is not feasible". Not only is it feasible, it's the right answer and the easy answer.
Just a quick hack at a solution:
private Control _anchorControl;
private List<Control> _parentChain = new List<Control>();
private void BuildChain()
{
foreach(var item in _parentChain)
{
item.LocationChanged -= ControlLocationChanged;
item.ParentChanged -= ControlParentChanged;
}
var current = _anchorControl;
while( current != null )
{
_parentChain.Add(current);
current = current.Parent;
}
foreach(var item in _parentChain)
{
item.LocationChanged += ControlLocationChanged;
item.ParentChanged += ControlParentChanged;
}
}
void ControlParentChanged(object sender, EventArgs e)
{
BuildChain();
ControlLocationChanged(sender, e);
}
void ControlLocationChanged(object sender, EventArgs e)
{
// Update Location of Form
if( _anchorControl.Parent != null )
{
var screenLoc = _anchorControl.Parent.PointToScreen(_anchorControl.Location);
UpdateFormLocation(screenLoc);
}
}

FormClosing delegate event problem

I have two forms named 'mainForm' and 'addRslt'. The idea is when users click on a button in mainForm, the addRslt form will Show() and then user will populate a TreeView. Now when user WANT to CLOSE this addRslt form, program will instead Hide() the form (using e.Cancel = true; ) so later if user reopen this he/she can add more things to the TreeView.
In my mainForm I have a button for showing this addRslt form, and also inside this button's click code, there is my FormClosing delegte which will detect and copy the contents od TreeView in addRslt form to a TreeView in mainForm.
Now the problem is I want to check for duplicated Nodes and do not add them to TreeView in mainForm. This is done right, but I also have a message box that tells the user that program had not added existing nodes! thats ok till now.. BUT problem is with each time I do this, this messagebox will appear N+1 times! I mean if I do it for first time, this message box appears 2 time and etc...
Here is my code! Sorry for long story!
private void menuFileAddTestResults_Click(object sender, EventArgs e)
{
addRslt.Show();
addRslt.FormClosing += delegate
{
foreach (TreeNode node in addRslt.treeViewSelectedFiles.Nodes)
{
TreeNode newNode = new TreeNode();
newNode.Text = node.Text;
newNode.Name = node.Name;
newNode.Tag = node.Tag;
if (!treeViewTestFiles.Nodes.ContainsKey(node.Name))
{
treeViewTestFiles.Nodes.Add(newNode);
}
else
{
countExist++;
}
}
if (countExist > 0)
{
MessageBox.Show(countExist.ToString() + " Test files are already exist in the list!");
}
countExist = 0;
};
}
You're adding a FormClosing handler every time you show it. Just add it once, when you set up the rest of what the form looks like. (Personally I'd probably split this into a separate method... I don't think it's a particularly appropriate use of a lambda expression - it's a fairly large chunk of code which doesn't refer to any variables declared within the containing method, so there's no real benefit.)
It looks like you are adding your inline implementation to the multicast delegate repeatedly.
Clearly this is not your intention. You will either need to subscribe one instance of the delegate as Jon Skeet suggests, or manage the subcriptions each time.

C# Drag & Drop Between ListViews

I'm trying to create a self-contained Winforms control called DragDropListView. It derives from ListView.
I have code that allows the user to sort list items within the control by dragging and dropping the items in the new location. I achieved that by overriding OnDragDrop, OnDragOver, OnDragEnter, OnItemDrag.
The issue I have is with dragging from one listview to a completely different listview. The event fires on the other list view as expected, but the method doesn't take a "sender" argument, so there's no good way to tell where the items are being dragged from, and no way I can figure out to actually grab the items being dragged. The current code works with stuff like "this.SelectedItems," but I'd like it to be "sender.SelectedItems".
I guess the reason there is no sender argument is that the control isn't supposed to responsible for knowing that much about its environment, and the host Form should handle the interaction between two controls, but I'm trying to build self contained controls that have this functionality, so letting it bleed onto the form isn't going to work.
Ideas?
I think you can know the ListView from the Items by listViewItem.ListView property, Check it.
I didn't test the code:
private void listView1_DragEnter(object sender, DragEventArgs e)
{
if (!e.Data.GetDataPresent(typeof(ListView.ListViewItemCollection)))
{
e.Effect = DragDropEffects.None;
return;
}
var items = (ListView.ListViewItemCollection)e.Data.GetData(typeof(ListView.ListViewItemCollection));
if (items.Count > 0 && items[0].ListView != listView1)
{
e.Effect = DragDropEffects.None;
return;
}
}
Check DragEventArgs , this sample in CodeProject [VB.Net]
Good luck!

Categories