I have very little experience making my own events. I'm currently using forms and controls to handle events, so I'm trying to stick to the WinForm way of dealing with events.
WinForm controls already have their own events. Since events are made with a certain delegate type, I have to match the delegate signature in the methods I use to handle what goes on during an event. As far as I can tell, this means I have to take in two parameters in my event handlers: a source Object and an EventArgs.
I'm trying to figure out how to pass various information between controls through DragDrop related events. I've been able to find various code snippets online for different situations, but I'd like to have a better understanding of how the information is actually passed around.
When it comes to DragDrop events in particular, it seems my information will be passed through a DataObject. That, in turn, is passed as a parameter to the DragDrop.DoDragDrop method.
This is where my understanding starts to diminish. In most examples I've seen, it looks like some sort of data format is specified. The data format itself is of type string. Usually the data format is passed along with the data into the DataObject.
What is this data format doing? Is it just showing the type of the data involved? I've seen examples where the data format was tested, and various actions took place depending on what the data format had been. Couldn't you just do a typeof(YourData) to check for the type? I don't understand how a data format is useful.
http://msdn.microsoft.com/en-us/library/ms741842.aspx
In the above link, the first example shows a DataObject being created with no data format being specified. It explains that the data format is automatically chosen and that your object is converted by default.
Can you just pass any object into the DataObject? Then when the DragDrop event takes place on the target control, can that control access the methods and fields of the object passed? Or will the object be converted into some other form by the DataObject? How about various structures?
I've also done some drag and dropping from a Windows explorer icon to my forms. I was able to get the icon's file path with some example code I found. It also used a data format.
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{
e.Effect = DragDropEffects.Copy;
}
SUMMARY:
I'm trying to get an understanding of how data is passed through WinForm events. I don't understand some of what I've seen in various DragDrop examples. I understand that data is somehow stored in various formats, and that there is a way to extract that data. I don't understand what a data format is used for. I don't understand exactly what sorts of data can be transferred through a DataObject. My understanding of EventArgs in general is fairly lacking.
Feel free to comment on anything I've mentioned here. If I stated something incorrectly, point it out. Anything that will help me understand this subject better is appreciated.
EDIT:
I decided to explain where I plan to go with this. Maybe someone can use what I'm trying to do as a way to explain some of what I asked.
I have a form that contains a certain type of control. I'm trying to make the placement of the controls highly customizable and dynamic. Whenever another control is added to the form by the user, every control is automatically repositioned to keep things orderly.
I'm currently trying to allow the user to drag a control around the Form to resposition it. Wherever the user decides to drop the control, all of the other controls will move out of the way to make room for the move control.
If I'm going to be able to move the dragged control and all the other controls on the form properly, I need to be able to get certain information from the dragged control. The main data that would need to be passed through the events would take the form of a Location property that uses a System.Drawing.Point structure.
Here's something to give you an idea of how it's done.
First drop two panels on a Form, and set their colors to two different colors.
public Form1()
{
InitializeComponent();
panel1.MouseDown += new MouseEventHandler(panel1_MouseDown);
panel2.AllowDrop = true;
panel2.DragEnter += new DragEventHandler(panel2_DragEnter);
panel2.DragDrop += new DragEventHandler(panel2_DragDrop);
}
void panel1_MouseDown(object sender, MouseEventArgs e)
{
panel1.DoDragDrop(panel1, DragDropEffects.Move);
}
void panel2_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetData(typeof(Panel)) != null) e.Effect = DragDropEffects.Move;
}
void panel2_DragDrop(object sender, DragEventArgs e)
{
Panel p = sender as Panel;//Not needed in this case. Could just write panel2.
Panel dropped = (Panel)e.Data.GetData(typeof(Panel));
dropped.Location = p.PointToClient(new Point(e.X, e.Y));
p.Controls.Add(dropped);
}
Then drag panel1 onto panel2.
I think this problem should not be solved using drag&drop. Drag&drop is meant as a way for multiple applications to exchange data. If the data you are dragging is only meaningful for the current process, don't use drag&drop.
You can just use a field (for example, a field on the instance of the containing Form) to store all the data you need.
Just to say the obvious: Drag&drop is not a way to drag around controls. You need a lot of custom logic for that, anyway. It's not like the built-in features of dnd would help you here.
Related
I am attempting a drag and drop in WPF.
My program allows you to drag coloured labels around the screen, in essence giving you the effect that squares are being dragged and dropped.
Bearing in mind that only the text is dragged rather then the control itself (i.e. not the colour):
What I would like to achieve is that when the drop event fires, I can change the colour of the label which I dragged the text from.
After consulting MSDN I've failed to figure out how to get at the control in question and after plenty of trial and error I'm hoping somebody here can help. https://msdn.microsoft.com/en-us/library/system.windows.forms.drageventargs.data(v=vs.110).aspx
Below is a sample of code which works, but the label who's colour I want to change is hard-coded, whereas in reality it could be any one of a number of labels.
private void ObjDrop(object sender, DragEventArgs e)
{
//testSquare is a hardcoded label
testSquare.Background = Brushes.LimeGreen;
//what I really need is for a variable to detect which label to access each time before I change its colour. So something along the lines of
Label myLabel = someCodeToGetTheLabelThatWasDragged;
myLabel.Background = Brushes.LimeGreen;
}
Hopefully I explained things well enough, thanks in advance.
You would use the IDataObject.GetData(Type) method to extract the the object in DragEventArgs.Data property. From there, you should be able to access whatever you store in the IDataObject.
This is a pretty general answer. To achieve said answer, that means you'll have to write your own class that implements IDataObject which contains the original control/control's name etc., then set the IDataObject when drag in initialized.
There may be an alternate solution available. I would watch what e.Data is in your current example, and try to work with that. If e.Data is of type Label, through casting, you could access the label that way, e.g. (e.Data as Label).Background = Brushes.LimeGreen;.
In a Drag and Drop implementation I've seen, the IDataObject contains the DropTarget and the DragSource, that way you can compare the two and allow/disallow things/types from being dragged and dropped by setting the Effect.
This page provides the solution for what i'm looking to do.
WPF Drag and Drop - Get original source info from DragEventArgs
The following code in particular used in the drop event method allowed me to achieve my aim
Label lbl = e.Data.GetData("System.Windows.Controls.Label") as Label;
After that I could manipulate the source of the drag whatever way I wished.
I'm working in Visual Studio 2010 and I'm dealing with C#; I've made a statusStrip that I intend to use as my tool-tip viewer, its .text attribute changing depending on the control the mouse has entered. I've got two textBoxes and I'm trying to make it such that entering the control fires a function called tooltipEnter, and leaving it fires a function called tooltipLeave. Here's my code for those two functions:
private void tooltipEnter(object sender, EventArgs e)
{
toolStripStatusLabel1.Text = this.AccessibleDescription;
}
private void tooltipLeave(object sender, EventArgs e)
{
toolStripStatusLabel1.Text = "Look here for tool-tips regarding the form!";
}
The problem with this is that, first, I'm not sure AccessibleDescription is the right attribute to saddle the description to, and I'm not sure of the most elegant way to do the toolStripStatusLabel1.Text assignment in the first place. Second, this in the program's frame of reference refers to the form on which these controls lay, not the controls themselves; How do I refer uniformly to "the control that just got entered" in a way that allows me to have just the one function for all entries, without having to make different ones for each control?
The problem with this is that, first, I'm not sure
AccessibleDescription is the right attribute to saddle the description
to, and I'm not sure of the most elegant way to do the
toolStripStatusLabel1.Text assignment in the first place.
AccessibleDescription is just some string instance referenced in your form, from this code. The text assignment is done in the only way possible. I'm not sure what your question is regarding this.
Second, this in the program's frame of reference refers to the form on
which these controls lay, not the controls themselves; How do I refer
uniformly to "the control that just got entered" in a way that allows
me to have just the one function for all entries, without having to
make different ones for each control?
sender is always the object from which the event was raised in the EventHandler delegate: msdn.microsoft.com/en-us/library/system.eventhandler.aspx
I want to fill an updatepanel with new dynamic controls in response to a button click.
However, I also want to be able to access the values of these dynamic controls in response to an event in one of the controls.
Specifically, I want the button to bring up two dropdownmenus. One of the menus (or both if need be) is in another update panel. I want the first menu in the update panel to change its data in response to a value getting selected in the other menu.
I think my problem is that when I cause a postback with one dropdownmenu I lose the other dropdownmenu because I created it in the button_click handler.
I know I should create dynamic controls in the Page_Init method (or so ive heard) but I only want the controls to show up if the button is clicked. There are other buttons on the page which need to create a different set of dynamic controls.
Thanks.
There are a lot of ways you can handle this, and which approach to take really depends on your project's requirements and your available resources.
The smoothest way to do it that would generally provide the best user experience would be to use a Javascript technique to hide and show controls as the page required them. JQuery is the library I would recommend for this. On the most basic level, you simply wire the control's activation (such as a button_click event) and hide or show a div containing the dynamic content as necessary, like so:
$("#control").show();
// and
$("#control").hide();
Alternatively, you can do this in C# by using the Visible property on many of the normal web controls for ASP.NET. The usual code-behind approach would look something like this:
private void btnControl_Click(object sender, EventArgs e)
{
var dynamicControl1 = FindControl("dynamicControl1");
dynamicControl.Visible = false; // or true, as the case may be
}
This particular approach is mostly attached to code-behinds, though, which I would encourage you to avoid if possible. They are practically impossible to test and will make projects a pain to work in. You can use a similar approach in the MVC3 framework, of course, it will just be a little different how you send and receive the control you are setting to not be visible. The other benefit this has that is kind of nice is that if something is set to not be visible, it tends not to even be displayed in the HTML generated by the templating engine (YMMV depending on the engine, but I know this is true in Razor). So someone viewing the source of your webpage won't be able to see inactive controls, which may or may not be something that appeals to you.
EDIT: I see the problem is less to do with how to display these things, and more with how to create and read them back given on-the-fly input.
I'm sure there's a way to do this with Javascript (which would more than probably be the cleanest and best way to do this), but I'm not good enough with JS to know the answer to that one. The way you would handle this in ASP.NET is make the div you're going to add controls to server-side (by using runat='server', then add what you need there. Again, the trivial code-behind approach would be something like:
private void btnControl_Click(object sender, EventArgs e)
{
foreach(var checkBoxChecked in chkBoxes.Where(x => x.Checked))
{
div.Controls.Add(new WebControl()) // or whatever the heck else it is you need.
}
}
This presumes that you have an IEnumerable<CheckBox> to iterate over, of course. You may also want an IList<WebControl> to keep track of all the junk you're adding. You will also need to make sure the CSS is applied properly to the div for the controls you're adding. And again, code-behinds are pretty awful and I use the example only because it'd be easy to spin up in a project to test for yourself.
I was just wondering if anyone has come across how to apply an input mask for a Tool Strip Combo Box in C#?
My drop down box gets populated over time with IP addresses, and I would like to restrict what the users are able to write in (Ex: can only input 3 '.'s, only numbers, etc).
So if anyone is able to help out I would really appreciate it!
Thanks in advance.
Edit
My design has changed so I now need to have a ToolStripComboBox
You could try catching the KeyUp event, then check that the input is valid. If not revert it to the last valid input. You would probably want to do something similar with the Validating event (make sure CausesValidation is true).
Another option would be to create a MaskedTextBox and place it so it covers the text box portion of the drop down menu. You would then need to wire up the events so the two form controls remained synced.
You could also look into the ErrorProvider class.
There are a couple of other ways (like a timer which runs ever .3 seconds), but those are usually performance hogs or difficult to maintain.
Update for regular expression comment:
If I was to do this I might use a regular expression or I might manually parse the string.
Either way the KeyUp and Validating events is where I would check the validation of the control. The KeyUp event gives me the option to check as they type while the Validating event allows me to validate when the control loses focus. Which you use will depend on what you want the user experience to be.
If you do not use the KeyUp event to validate, you could add a timer which runs 5 seconds after the last key press. This way the control would not have to lose focus for the error to show.
Update for edited question and comment:
You could not use Format event as your question was on how to format user input, not how things are added to the list. As such that solution does not work with ToolStripComboBox or with ComboBox.
After reading the documentation for ToolStripControlHost, you might be able to cast ToolStripComboBox to ComboBox. If not then you could use the ToolStripControlHost to place the ComboBox onto your form. - This is incorrect or unnecessary, please see update below the quote.
ToolStripControlHost is the abstract base class for ToolStripComboBox, ToolStripTextBox, and ToolStripProgressBar. ToolStripControlHost can host other controls, including custom controls, in two ways:
Construct a ToolStripControlHost with a class that derives from Control. To fully access the hosted control and properties, you must cast the Control property back to the actual class it represents.
Extend ToolStripControlHost, and in the inherited class's default constructor, call the base class constructor passing a class that derives from Control. This option lets you wrap common control methods and properties for easy access in a ToolStrip.
Use the ToolStripControlHost class to host your customized controls or any other Windows Forms control.
To customize a ToolStripItem, derive from ToolStripControlHost and create a custom implementation. You can override methods such as OnSubscribeControlEvents to handle events raised by the hosted controls, and you can put custom functionality into properties to enhance the hosted control.
Update:
According to the ToolStripComboBox documentation you can access the underlying ComboBox through ToolStripComboBox's ComboBox property.
This is why I usually read the documentation on a control before I use it. I might not understand it, but at least I will have an idea what to look for. :)
You should create Format event like this:
private void comboBox1_Format(object sender, ListControlConvertEventArgs e)
{
e.Value = GetFullIpFormat((string)e.Value);
}
And here is code for formating values:
string GetFullIpFormat(string value)
{
string[] ip = new string[4];
for (int i = 0; i < ip.Length; i++)
{
ip[i] = GetIpPart(i, value);
}
return string.Format("{0:###}.{1:###}.{2:###}.{3:###}", ip[0], ip[1], ip[2], ip[3]);
}
string GetIpPart(int partNumber, string ip)
{
string result = "000";
int iLen = 3;
ip = ip.Replace(".", "");
int iStart = partNumber * iLen;
if (ip.Length > iStart)
{
result = ip.Substring(iStart);
if (result.Length > iLen)
{
result = result.Substring(0, iLen);
}
}
return result;
}
This will do formating for you.
Alternativly you can check input on same event for numbers.
This will do the job for you, happy coding! :)
I'm attempting to use the ScintillaNET control in an application I am working on. I drag and drop the control into my form and run form. The control appears on the form. This is good. In addition, if I set any of the properties in the control's properties editor (ConfigurationManager.Language, for example), I am able to type in that language and see syntax highlighting occur.
Where I run into problems is when I attempt to change properties programmatically. For example, I attempt to load text from a file into the form (I'm doing this in the form's Load). The text doesn't display. I also can't seem to show the line numbers or do any other number of tasks (including programmatically change the Language).
Any idea what I may be doing wrong? Even something as simple as the code below doesn't seem to work:
private void scintilla1_Load(object sender, EventArgs e)
{
scintilla1.ConfigurationManager.Language = "xml";
}
Simply add scintilla1.ConfigurationManager.Configure();
private void scintilla1_Load(object sender, EventArgs e)
{
scintilla1.ConfigurationManager.Language = "xml";
scintilla1.ConfigurationManager.Configure();
}
After spending some time playing around with the different events, it appears that I cannot affect the Scintilla control until after it is already visible. Hence, the "Load" event does not let me make any programmatic changes to the control until I've set it visible.
It's a little strange, and seems sort of pointless to me to have the Load event at all, but I just wanted to let everybody know what is happening in case someone else ran into the same problem.