I'm trying to make an application where I want to drag and drop files from explorer directly to application and a DataGridView updates its entries with the information about the file dropped.
Doing that wasn't an issue but what exactly I wanted is to update the form's UI and display some sort of message like 'Drop files here to update' just when I am over the application holding the file (and not dropped yet).
I found Control.GiveFeedback can be used to achieve what I want but somehow even after subscribing to the event, Its not being called.
Here is how I'm handling DragDrop event:
private void dataGridView1_DragDrop(object sender, DragEventArgs e)
{
FileInfo[] DroppedFiles = ((string[])e.Data.GetData(DataFormats.FileDrop)).Select(x => new FileInfo(x)).ToArray();
foreach (FileInfo File in DroppedFiles)
{
TrackInfo Track = new TrackInfo(File.FullName);
PlaylistSource.Add(Track);
}
}
Thank you in advanced.
DragOver and DragLeave were the events I had to subscribe in order to let the application aware about a potential DragDrop event.
I handled the event like this:
private void label1_DragOver(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{
e.Effect = DragDropEffects.Link;
//Updating UI Controls when file dragged over
label1.BackColor = Color.Green;
label1.ForeColor = Color.White;
}
}
private void label1_DragLeave(object sender, EventArgs e)
{
//Updating UI Controls when file no longer being dragged over
label1.BackColor = SystemColors.Control;
label1.ForeColor = Color.Black;
}
Of course, you must not forget to set the control's AllowDrop property to actually let the control become "DragDrop Aware".
Related
So I am making an app in C# where it creates/edits existing .ini files. One of the features I am trying to add is that if I make changes to the .ini file via the c# app I created, and either try to close the app, open another .ini file or create a new file, it should prompt the user if they want to save the file. To accomplish this, I have a flag called dataChanged. In the TextChanged events in for the multiple textboxes, I set dataChanged = true; since changes were made to the file. However, for some reason as soon as I open the app, all the TextChange events fire up so even if I don't enter any values in the various textboxes, when I close the app, it prompts me to save the file (it shouldn't!).
App UI:
User inputs text in the textboxes.
Part of code regarding the 4 textboxes:
private void TextBox_TextChanged(object sender, TextChangedEventArgs e) //ifrs installer
{
dataChanged = true;
}
private void TextBox_TextChanged_1(object sender, TextChangedEventArgs e) //ifrs patchfile
{
dataChanged = true;
}
private void textBox3_TextChanged(object sender, TextChangedEventArgs e)
{
dataChanged = true;
}
private void textBox4_TextChanged(object sender, TextChangedEventArgs e)
{
dataChanged = true;
}
TextChanged event fires even when you set some Text. Apparently you set some initial text when app is loading.
You can subscribe to the event mannually after you set the initial value.
textBox4.TextChanged += textBox4_TextChanged;
or unsubscribe before you set the value and subscribe after that.
textBox4.TextChanged -= textBox4_TextChanged;
textBox4.Text = "Initial Value";
textBox4.TextChanged += textBox4_TextChanged;
Sounds to me like you're programmatically setting the textBoxN.Text properties.
What you might want to do is add an if (appInitialized) around your dataChanged = true; and only set appInitialized to true after the application is loaded, perhaps in your Form_Load event. This way, the initial loading doesn't set your variable. Another option is to only register the TextChanged event after you have already set the initial values. My guess is you registered the event using the designer and as a result it's firing for those initial settings because of where the designer adds event registration. Instead do the
textBox4.TextChanged += textBox4_TextChanged;
// Etc. for each text box
yourself after the .Text properties are set. Again, perhaps in your Form_Load.
I'm guessing you are loading the ini file when the program loads and this triggers to text changed event. I suggest doing something like this.
private void Form1_Load(object sender, EventArgs e)
{
LoadData();
}
private bool _LoadingData = false;
private bool _DataChanged = false;
private void LoadData()
{
try
{
_LoadingData = true;
// Load data
}
finally
{
_LoadingData = false;
}
}
public void DataChanged()
{
if (_LoadingData == false)
{
_DataChanged = true;
}
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
DataChanged();
}
I've got a basic owner-drawn listview (in Details mode) set up with the following handlers:
void SinkHandlerDrawColumnHeader(Object Sender, DrawListViewColumnHeaderEventArgs E)
{
E.DrawDefault = true;
}
void SinkHandlerDrawItem(Object Sender, DrawListViewItemEventArgs E)
{
E.DrawDefault = true;
TrackingMessage Data = (TrackingMessage)E.Item.Tag;
E.Item.SubItems[0].Text = Data.Line().ToString();
E.Item.SubItems[1].Text = Data.Message();
}
void SinkHandlerDrawSubItem(Object Sender, DrawListViewSubItemEventArgs E)
{
E.DrawDefault = true;
}
While the above code works, the listview is constantly being redrawn whenever it's visible. Any idea why?
EDIT: The problem was with my modifying the subitem text inside the owner draw handler. Using E.Graphics.DrawString to render the text instead fixed the issue.
Per my comment, changing data in a paint event is usually a bad design. Paint events should just paint, and very little else. By changing the data in the paint event, you were forcing the paint event to draw itself again and again.
If you need to modify the data, you need a different event.
I need to do drag and drop using treeview in c#.For that i heard 3 events are the most common
1.itemDrag
2.DragDrop and 3.DragEnter.
whereas here itemDrag event is firing for me while dragging from a treeview ,but rest both the events are not firing for me.Tried many solutions and now came here for an solution
private void treeView1_ItemDrag(object sender, ItemDragEventArgs e)
{
string[] strItem = e.Item.ToString().Split(':');
DoDragDrop(strItem[1], DragDropEffects.Copy | DragDropEffects.Move); }
the above method fires ,
private void treeView1_DragEnter(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Move;
}
the bove dragEnter event is not firing ,similarly the dragDrop event is also not firing.Why it's so??
Am dragging from the treeview and need to paste in PowerPoint or Word. (ie) treeview is something like an AddIn for Office Tools.
Regards,
Arshad
Allow Drop AND..
Ok, assuming you have all of your events being declared/created in the Form_Load... e.i.
:
tlAssemblies.DragDrop +=tlAssemblies_DragDrop;
tlAssemblies.MouseDown +=tlAssemblies_MouseDown;
tlAssemblies.MouseMove +=tlAssemblies_MouseMove;
tlAssemblies.DragEnter +=tlAssemblies_DragEnter;
tlAssemblies.DragOver += tlAssemblies_DragOver;
The drag Event is for when you fire the drag event inside your treeView which is why it is working. The dragEnter is when you enter the boundaries of a different* control.
i.e you want to drag from treeview 1 into treeview2.
If you are not trying to drag the item into a different control dragEnter is wrong.
Here is a drag drop event sample :
private void tlAssemblies_DragDrop(object sender, DragEventArgs e)
{
if (sender == null)
return;
Point p = tlAssemblies.PointToClient(new Point(e.X, e.Y));
TreeListNode dragNode = e.Data.GetData(typeof(TreeListNode)) as TreeListNode;
TreeListNode targetNode = tlAssemblies.CalcHitInfo(p).Node;
if (targetNode == null)
{
return;
}
}
Not sure if it is possible but you may want to change the dragEnter code you have and simply use it in the drag event i.e.
e.Effect = DragDropEffects.Move;
If you are not leaving the same control you are dragging both to and fro, might as well show the drag movement.
Another thing you could do is on the treeView_MouseMove Event.
private void tlAssemblies_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left && downHitInfo != null)
{
Size dragSize = SystemInformation.DragSize;
Rectangle dragRect = new Rectangle(new Point(downHitInfo.HitPoint.X - dragSize.Width / 2,
downHitInfo.HitPoint.Y - dragSize.Height / 2), dragSize);
if (!dragRect.Contains(new Point(e.X, e.Y)))
{
DataRow row = viewProduct.GetDataRow(downHitInfo.RowHandle);
if(row != null)
tlAssemblies.DoDragDrop(row, DragDropEffects.Move);
//viewProduct.GridControl.DoDragDrop(row, DragDropEffects.All);
downHitInfo = null;
DevExpress.Utils.DXMouseEventArgs.GetMouseArgs(e).Handled = true;
}
}
}
From your provided code, I cannot see that you have implemented the DragDrop event nor have set the AllowDrop property on the controls involved, which is needed along with the two other events in order to perform a drag and drop.
Here is sample snatched directly from MSDN, which uses two treeviews to move nodes in between. Add a couple of treeviews, add some root and child nodes, and wire up these events. Remember the AllowDrop property.
I have added a couple of Debug.WriteLine() to help with the debugging while testing this. Can be hard to do with breakpoints ;-)
NOTE: For brewity I have not supplied the event wiring code, nor the code for creating sample nodes. If needed this can be found in the referenced article. Otherwise add those using the property window.
Sample code:
private void treeView_ItemDrag(object sender, ItemDragEventArgs e)
{
Debug.WriteLine("ItemDrag fired!");
DoDragDrop(e.Item, DragDropEffects.Move);
}
private void treeView_DragEnter(object sender, DragEventArgs e)
{
Debug.WriteLine("TreeView DragEnter fired!");
e.Effect = DragDropEffects.Move;
}
private void treeView_DragDrop(object sender, DragEventArgs e)
{
Debug.WriteLine("TreeView DragDrop fired!");
TreeNode NewNode;
if (e.Data.GetDataPresent("System.Windows.Forms.TreeNode", false))
{
Point pt = ((TreeView)sender).PointToClient(new Point(e.X, e.Y));
TreeNode DestinationNode = ((TreeView)sender).GetNodeAt(pt);
NewNode = (TreeNode)e.Data.GetData("System.Windows.Forms.TreeNode");
if (DestinationNode.TreeView != NewNode.TreeView)
{
DestinationNode.Nodes.Add((TreeNode)NewNode.Clone());
DestinationNode.Expand();
//Remove Original Node
NewNode.Remove();
}
}
}
I'm trying to build a simple interface that allows users to drop files into a listBox to add them to a process, and to drag them out to remove them. Everything is working fine, but I'd like to add one feature to make it just a tad more sophisticated.
Right now, I have the removal of the item tied to the DragLeave event, which means that as soon as the mouse leaves the box, the item is removed. But I'd like for users to be able to change their minds. In other words, if they realize they're dragging the wrong file out, I'd like them to be able to move the mouse back into the listBox and release the mouse to cancel the action. I'm thinking that means I need to be able to capture the MouseUp event instead of the DragLeave event. But that hasn't been successful so far.
Below is the code I'm currently using for removing files dragged out. How can I modify to keep the files from being removed form the list until the user lets the mouse button go?
private void listBox1_MouseDown(object sender, MouseEventArgs e)
{
if (listBox1.Items.Count == 0)
{
return;
}
int index = listBox1.IndexFromPoint(e.X, e.Y);
string s = listBox1.Items[index].ToString();
DragDropEffects dde1 = DoDragDrop(s, DragDropEffects.All);
}
private void listBox1_DragLeave(object sender, EventArgs e)
{
ListBox lb = sender as ListBox;
lb.Items.Remove(lb.SelectedItem);
}
Edit 2013/05/16
The comments and answers so far have been useful, but I realize my question isn't clear enough. In this case, I'm displaying a dialog separate from the parent form that is basically as big as the listBox. When someone drags a file out of the list, they're dragging it off the form completely. Have I backed myself into a corner by doing this? I recognize I'm making it harder than it has to be, but I'd still like to see how it would work if it's possible.
Here's a fairly quick hack approach to gaining the functionality you want:
public object lb_item = null;
private void listBox1_DragLeave(object sender, EventArgs e)
{
ListBox lb = sender as ListBox;
lb_item = lb.SelectedItem;
lb.Items.Remove(lb.SelectedItem);
}
private void listBox1_DragEnter(object sender, DragEventArgs e)
{
if (lb_item != null)
{
listBox1.Items.Add(lb_item);
lb_item = null;
}
}
private void listBox1_MouseDown(object sender, MouseEventArgs e)
{
lb_item = null;
if (listBox1.Items.Count == 0)
{
return;
}
int index = listBox1.IndexFromPoint(e.X, e.Y);
string s = listBox1.Items[index].ToString();
DragDropEffects dde1 = DoDragDrop(s, DragDropEffects.All);
}
private void Form1_DragDrop(object sender, DragEventArgs e)
{
lb_item = null;
}
Every time the user drags an item out of the box, it's saved temporarily until the user drops it somewhere else or mouses down on a new item in the list.
Note the important part of this is detecting when and where the user let's go of that mouse, which is the rationale behind handling the DragDrop event of Form1, the parent of listBox1.
Depending on the sophistication and density of the rest of your layout, where you handle DragDrop could be much different for you. This is why it's kind of "hacky", but it's also quite simple. It shouldn't matter, though, where or how many times you null lb_item since it pertains only to that specific ListBox.
I suppose another way to do it would be to track the user's mouse states and act accordingly, which may be more appropriate for you if it's inconceivable to handle a lot of DragDrop stuff.
EDIT: If you wanted to be REAL thorough, you could enumerate through every control of the base form using foreach and programmatically append a handler for the DragDrop event to that control, then remove it when done... but that may be getting a little nutty. I'm sure someone has a better approach.
Is it possible to have a WPF window/element detect the drag'n'dropping of a file from windows explorer in C# .Net 3.5? I've found solutions for WinForms, but none for WPF.
Try the following :
private void MessageTextBox_Drop(object sender, DragEventArgs e)
{
if (e.Data is DataObject && ((DataObject)e.Data).ContainsFileDropList())
{
foreach (string filePath in ((DataObject)e.Data).GetFileDropList())
{
// Processing here
}
}
}
private void MessageTextBox_PreviewDragEnter(object sender, DragEventArgs e)
{
var dropPossible = e.Data != null && ((DataObject)e.Data).ContainsFileDropList();
if (dropPossible)
{
e.Effects = DragDropEffects.Copy;
}
}
private void MessageTextBox_PreviewDragOver(object sender, DragEventArgs e)
{
e.Handled = true;
}
Unfortunately, TextBox, RichTextBox, and FlowDocument viewers always mark drag-and-drop events as handled, which prevents them from bubbling up to your handlers. You can restore drag-and-drop events being intercepted by these controls by force-handling the drag-and-drop events (use UIElement.AddHandler and set handledEventsToo to true) and setting e.Handled to false in your handler.
Turns out I couldn't drop onto my TextBox for some reason, but dropping onto buttons works fine. Got it working by adding 'AllowDrop="True"' to my window and adding drop event handler to button consisting of:
private void btnFindType_Drop(object sender, DragEventArgs e)
{
if (e.Data is System.Windows.DataObject &&
((System.Windows.DataObject)e.Data).ContainsFileDropList())
{
foreach (string filePath in ((System.Windows.DataObject)e.Data).GetFileDropList())
{
// Processing here
}
}
}
I had similar Issue, The drop events and drag enter events were not fired. The issue was with the windows User Account Settings. Set it to least secure setting and try the same code it works.