Drag and drop files into WPF - c#

I need to drop an image file into my WPF application. I currently have a event firing when I drop the files in, but I don't know how what to do next. How do I get the Image? Is the sender object the image or the control?
private void ImagePanel_Drop(object sender, DragEventArgs e)
{
//what next, dont know how to get the image object, can I get the file path here?
}

This is basically what you want to do.
private void ImagePanel_Drop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{
// Note that you can have more than one file.
string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
// Assuming you have one file that you care about, pass it off to whatever
// handling code you have defined.
HandleFileOpen(files[0]);
}
}
Also, don't forget to actually hook up the event in XAML, as well as setting the AllowDrop attribute.
<StackPanel Name="ImagePanel" Drop="ImagePanel_Drop" AllowDrop="true">
...
</StackPanel>

The image file is contained in the e parameter, which is an instance of the DragEventArgs class.
(The sender parameter contains a reference to the object that raised the event.)
Specifically, check the e.Data member; as the documentation explains, this returns a reference to the data object (IDataObject) that contains the data from the drag event.
The IDataObject interface provides a number of methods for retrieving the data object that you're after. You'll probably want to start by calling the GetFormats method in order to find out the format of the data that you're working with. (For example, is it an actual image or simply the path to an image file?)
Then, once you've identified the format of the file being dragged in, you'll call one of the specific overloads of the GetData method to actually retrieve the data object in a particular format.

Additionally to answer of A.R. please note that if you want to use TextBox to drop you have to know following stuff.
TextBox seems to have already some default handling for DragAndDrop. If your data object is a String, it simply works. Other types are not handled and you get the Forbidden mouse effect and your Drop handler is never called.
It seems like you can enable your own handling with e.Handled to true in a PreviewDragOver event handler.
XAML
<TextBox AllowDrop="True" x:Name="RtbInputFile" HorizontalAlignment="Stretch" HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible" />
C#
RtbInputFile.Drop += RtbInputFile_Drop;
RtbInputFile.PreviewDragOver += RtbInputFile_PreviewDragOver;
private void RtbInputFile_PreviewDragOver(object sender, DragEventArgs e)
{
e.Handled = true;
}
private void RtbInputFile_Drop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{
// Note that you can have more than one file.
string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
var file = files[0];
HandleFile(file);
}
}

Related

C# Forms. How do I refer to a control from within that control

I wrote a piece of code which convert the written language to Hebrew (via a reference I developed).
When for example, when I enter a textbox control and I need it to get writing in Hebrew I add to its Enter event the following:
private void txtTestDirectionRTL_Enter(object sender, System.EventArgs e)
{
HebChng ();
txtTestDirectionRTL.RightToLeft = RightToLeft.Yes;
}
The HebChng convert the input language to Hebrew.
Now, the second line of code determines the flow direction for that textbox.
What I would like to do is to refer to that control by other meanings than its explicit name.
The keyword "this" refers to the class. Is there anything that I can use to refer to the name of the control I'm in?
Can this be done?
you can get the object via the sender your event function like so
(sender as TextBox).RightToLeft = RightToLeft.Yes;
The method has a parameter "object sender" - you can use that by casting it to the correct class. For example:
private void txtTestDirectionRTL_Enter(object sender, System.EventArgs e)
{
HebChng ();
TextBox myControl = (TextBox)sender;
myControl.RightToLeft = RightToLeft.Yes;
}
Note that this is applicable to all control event handlers - the first parameter is an object which is a reference to the originating control (i.e. the "sender"). This should allow you to use the same event handler for multiple controls if you override the handlers automatically generated by Visual Studio.

Reference click method from another source file in XAML?

I have a button with a click method assigned to it. I'd like to move that method to another CS file so I may reuse it in other places. Is it possible in XAML to reference a method, click method, from a CS source file outside of the Pages source file?
<Button x:Name="TheRedButton" Click="DoNotPressTheRedButton_Click" />
I want to locate DoNotPressTheRedButton_Click in another source file.
ButtonMethods.cs
and then use it in my Page from XAML
MyPage.xaml
What do I need to write in XAML in order to do this?
I thought I need:
xmlns:helpermethods="using:CoreProject.HelperMethods"
then,
<Button x:Name="TheRedButton" Click="helpermethods:ButtonMethods.DoNotPressTheRedButton_Click" />
But I'm getting compiler errors... CS1002 and CS1513. So obviously it's not the right syntax. Is this even possible?
Easy peasy:
<Button Click="{x:Bind helpermethods:ButtonMethods.ButtonClick}" />
Or in WPF:
<Button Click="{x:Static helpermethods:ButtonMethods.ButtonClick}" />
C#:
public static class ButtonMethods
{
public static RoutedEventHandler ButtonClick => Button_Click;
public static void Button_Click(object sender, RoutedEventArgs e)
{
// stuff
}
}
You could call your method in ButtonMethods from the click handler of your TheRedButton.
Like this:
private void OnSomebodyClickedTheRedButtonWhenTheyWereNotMeantTo(object sender, RoutedEventArgs args)
{
// do some other stuff with sender - find out which button was clicked, etc.
ButtonMethods.RedButtonClicked(sender, args);
}
This would allow you to also do "other stuff" that you might need, within this class, from this event handler (if you wanted to).
Make sure your method is static, otherwise you would need to (unnecessarily) create an instance of the ButtonMethods class each time.

Handle all elements Holding event

I have an idea of implementing holding event handler for all text-type controls ( label, textbox, passwordbox, hyperlink etc. ) in order to show message popup for allowing suggest a better translation of this text.
Is it possible to implement such type of event handler for all controls that get added/removed from/to visual tree.
Without doing such for each element:
<TextBox Holding="HoldingEventHandler"/>
I have tried this in my MainPage.xaml.cs:
AddHandler(Control.HoldingEvent, new RoutedEventHandler(HoldingOccured), true);
But it fails with exception:
Value does not fall within the expected range.
If you implement Holding in xaml and ask for new handler the system will generate the follow callback.
private void WindowsPage_Holding(object sender, HoldingRoutedEventArgs e)
{
}
So, thiis is a correct call parameters.
AddHandler(Control.HoldingEvent, new HoldingEventHandler(HoldingOccured), true);

Getting the actual dropped UIElement object on Drop Event in UWP

I'm converting an application I wrote in WinForms to UWP and as far as I can tell, the Drag n Drop functionality is slightly different. Here is my code from my WinForms application that I used to get the 'dragged' object, which is a Control called FunctionButton;
private void flowLayoutPanel_ActiveGroup_DragDrop(object sender, DragEventArgs e)
{
Function_Button draggedItem;
/* Check if the dragged item is one of the allowed dragged item TYPES. */
draggedItem = (Function_Button)e.Data.GetData(type);
if (draggedItem != null)
{
//DO STUFF
}
}
I'm currently setting my own StringDataFormats when the Drag Starts for the information i need, which I read using DataView.GetDataAsync(), although how can I get direct access to the dragged UIElement object in UWP?
I am not sure if this is the best way but it works.
First you need to handle the DragStarting event and store the UIElement that will be dragged inside the DataPackage that is exposed by the Data property. The DataPackage type seems to be very conditioned on files and file formats but fortunately it has a general purpose dictionary exposed by property Properties.
<local:YourElement CanDrag="True" DragStarting="dragStarting">
</local:YourElement>
private void dragStarting(UIElement sender, DragStartingEventArgs args)
{
args.Data.Properties.Add("anykeyworks", sender);
}
Next you handle the Drop event as follows:
<local:YourOtherElement AllowDrop="True" DragOver="dragOver" Drop="drop">
</<local:YourOtherElement>
private void drop(object sender, DragEventArgs e)
{
UIElement element = e.DataView.Properties["anykeyworks"] as UIElement;
}
private void dragOver(object sender, DragEventArgs e)
{
e.AcceptedOperation = DataPackageOperation.Copy;
}
If you do not implement the DragOver handler, the Drop event won't be fired.
As you've known, the drag and drop function in UWP is different from what in WinForms. In UWP apps, what we are dragging and dropping is not the UIElement but the DataPackage. So we can't get direct access to the dragged UIElement object.
I'm not sure why you want to get the dragged or dropped UIElement object. If you want to do some checks while dropping, I think you can check the content of the DataPackageView class which is exposed by DataView property.
For more information about drag and drop function in UWP, please see Drag and drop and also the official Drag and drop sample on GitHub.

ScintillaNET Autocomplete and CallTip

I am using ScintillaNET to make a basic IntelliSense editor. However, I have a problem when I call _editor.CallTip.Show("random text") in the AutoCompleteAccepted Event.
If I type pr for example, and scroll and select printf in the drop-down list, it goes to my AutoCompleteAccepted event and when I call the CallTip.Show, the rest of the word does not get added (however, without that CallTip code, the rest of the word is filled).
So, if I typed pr then it stays pr and I get my CallTip. How do I make sure the rest of the word gets inserted AND the CallTip shows?
Is the AutoCompleteAccepted Event not the right place to call it? If so, where should I call the CallTip.Show so that it works side-by-side with my AutoComplete?
Finally figured it out! The AutoCompleteAccepted Event isn't the right place to put CallTip.Show
What is going on is the fact that when AutoCompleteAccepted Event is called and you add text to the ScintillaNET control, it takes time for the UI to update and so, when you call to show the CallTip, it interferes with the text being inserted into the control.
The better way to do it is to call CallTip.Show in the TextChanged event, as they you know that the text has been inserted when the AutoCompleteAccepted Event was called.
It would now look something like this:
String calltipText = null; //start out with null calltip
...
private void Editor_TextChanged(object sender, EventArgs e)
{
if (calltipText != null)
{
CallTip.Show(calltipText); //note, you may want to assign a position
calltipText = null; //reset string
}
...
}
...
private void Editor_AutoCompleteAccepted(object sender, AutoCompleteAcceptedEventArgs e)
{
if (e.Text == "someThing")
{
/* Code to add text to control */
...
calltipText = "someKindOFText"; //assign value to calltipText
}
}
That is essentially what can be done to ensure the AutoComplete fills correctly and you get the CallTip to show.
Just note, that the CallTip MAY end up in unintended places, so it is recommended to set the value of where you want the CallTip to show up

Categories