I'm making Windows Form App in C# and best control for what I need is ActiveX Control (Calendar). The problem is that I need drag and drop but Control that I use does not have events for it (only positive thing is that it has property "AllowDrop"). (Control is Xtreme Calendar - Codejock)
I did somehow managed to do it. Using ListBox and it's events MouseDown (to get data with IndexFromPoint method) and MouseUp (to call Calendar's DoubleClick event).
private string name = string.Empty;
private void lstNames_MouseDown(object sender, MouseEventArgs e)
{
if (lstNames.Items.Count == 0)
name = string.Empty;
else
{
int index = lstNames.IndexFromPoint(e.X, e.Y);
name = lstNames.Items[index].ToString();
}
}
private void lstNames_MouseUp(object sender, MouseEventArgs e)
{
if (name != string.Empty)
CalendarControl_DblClick(name, null);
}
Related
Learning WPF with MacDonald's "Pro WPF 4.5 in C#," focusing on Ch5, Events.
How would I write a generic event handler that works with both Labels and TextBoxes to process the MouseDown event initializing a drag & drop procedure?
Here is my TextBox handler:
private void tBSource_MouseDown(object sender, EventArgs e) {
TextBox tBox = (TextBox)sender;
DragDrop.DoDragDrop(tBox, tBox.Text, DragDropEffects.Copy);
}
And my Label handler:
private void lblSource_MouseDown(object sender, EventArgs e) {
Label lbl = (Label)sender;
DragDrop.DoDragDrop(lbl, lbl.Content, DragDropEffects.Copy);
}
As you can see, I'm using the Content property and the Text property, depending on which object starts the event. If I try to use the same property for both senders, I get build errors (regardless of which I use). If I can avoid duplication, I would be very happy. Should I chunk a conditional out into another function and call that in the handler to determine what property should be used?
you could do something like this:
private void Generic_MouseDown(object sender, EventArgs e)
{
object contentDrop = string.Empty;
//Label inherits from ContentControl so it doesn't require more work to make work for all controls inheriting from ContentControl
if (sender is ContentControl contentControl)
{
//If you don't want to filter other content than string, you can remove this check you make contentDrop an object
if (contentControl.Content is string)
{
contentDrop = contentControl.Content.ToString();
}
else
{
//Content is not a string (there is probably another control inside)
}
}
else if (sender is TextBox textBox)
{
contentDrop = textBox.Text;
}
else
{
throw new NotImplementedException("The only supported controls for this event are ContentControl or TextBox");
}
DragDrop.DoDragDrop((DependencyObject)sender, contentDrop, DragDropEffects.Copy);
}
Let me know if you have any question
I have a DevExpress grid, which is disabled on screen. When I click the control, I want it to become enabled. Right now I have a click event set up for the grid:
private void gridPSR_Click(object sender, EventArgs e)
{
gridPSR.Enabled = true;
}
This isn't working. How should I be going about this?
Disabled controls do not receive windows messages, so you will never get the click message on that control. Assuming this is Winforms, you can listen for the click on the form (or whatever control is hosting this grid) and check if the click location is in the rectangle of the disabled control and then enable the control accordingly:
void Form1_MouseClick(object sender, MouseEventArgs e)
{
if (gridPSR.ClientRectangle.Contains(e.Location))
{
gridPSR.Enabled = true;
}
}
I know it's an old post but for me bounds worked instead of ClientRectangle
private void OnPanelMouseClick(object sender, MouseEventArgs e)
{
if ((e.Button == MouseButtons.Left) &&
myControl.Bounds.Contains(e.Location) &&
!myControl.Enabled)
{
myControl.Enabled = true;
}
}
Where myControl is member variable of your control instance. OnPanelMouseClick handler should be linked with MouseClick event of form or container that holds control.
In this code I am setting an event on a disabled TextBox control called 'txtNumLabels'. I tested this code with the text box both on a Form and also with having it within a GroupBox container.
Set an event in the constructor after the 'InitializeComponent();'
this.txtNumLabels.Parent.MouseClick += new System.Windows.Forms.MouseEventHandler(this.txtNumLabels_Parent_MouseClick);
Here is the event handler -
private void txtNumLabels_Parent_MouseClick(object sender, MouseEventArgs mouseEvent)
{
// The Bounds property of a control returns a rectangle of its Location and Size within its parent control
Rectangle rect = txtNumLabels.Bounds;
// Other method that gets the same rectangle -
// Point t = txtNumLabels.Location;
// Size ts = txtNumLabels.Size;
// Rectangle rect = new Rectangle(t, ts);
if (rect.Contains(mouseEvent.Location))
{
txtNumLabels.Enabled = true;
}
}
I have made a custom Number Keypad control that I want to place in my winform application. All of the buttons have an OnClick event to send a value to the focused textbox in my form where I have placed my custom control. Like this:
private void btnNum1_Click(object sender, EventArgs e)
{
if (focusedCtrl != null && focusedCtrl is TextBox)
{
focusedCtrl.Focus();
SendKeys.Send("1");
}
}
focusedCtrl is supposed to be set on the MouseDown event of the button like this:
private void btnNum1_MouseDown(object sender, EventArgs e)
{
focusedCtrl = this.ActiveControl;
}
where this.ActiveControl represents the active control on the form.
My problem is that the button always receives the focus before the event detects what the focused control was previously. How can I detect which control had the focus before the button got the focus? Is there another event I should be using? Thanks in advance!
EDIT: Also, I would rather not use the GotFocus event on each textbox in the form to set focusedCtrl since that can be tedious and because I would like to have all the coding of my custom control be in the control itself and not on the form where it is placed. (I will do this, though, if there is no other practical way to do what I am asking)
Your requirement is fairly unwise, you'll want some kind of guarantee that your button isn't going to poke text into inappropriate places. You really do need to have the form co-operate, only it knows what places are appropriate.
But it is not impossible, you can sniff at input events before they are dispatched to the control with the focus. In other words, record which control has the focus before the focusing event is fired. That's possible in Winforms with the IMessageFilter interface.
Add a new class to your project and paste the code shown below. Compile. Drop the new control from the top of the toolbox onto your form, replacing your existing buttons.
using System;
using System.Windows.Forms;
class CalculatorButton : Button, IMessageFilter {
public string Digit { get; set; }
protected override void OnClick(EventArgs e) {
var box = lastFocused as TextBoxBase;
if (box != null) {
box.AppendText(this.Digit);
box.SelectionStart = box.Text.Length;
box.Focus();
}
base.OnClick(e);
}
protected override void OnHandleCreated(EventArgs e) {
if (!this.DesignMode) Application.AddMessageFilter(this);
base.OnHandleCreated(e);
}
protected override void OnHandleDestroyed(EventArgs e) {
Application.RemoveMessageFilter(this);
base.OnHandleDestroyed(e);
}
bool IMessageFilter.PreFilterMessage(ref Message m) {
var focused = this.FindForm().ActiveControl;
if (focused != null && focused.GetType() != this.GetType()) lastFocused = focused;
return false;
}
private Control lastFocused;
}
Control focusedCtrl;
//Enter event handler for all your TextBoxes
private void TextBoxesEnter(object sender, EventArgs e){
focusedCtrl = sender as TextBox;
}
//Click event handler for your btnNum1
private void btnNum1_Click(object sender, EventArgs e)
{
if (focusedCtrl != null){
focusedCtrl.Focus();
SendKeys.Send("1");
}
}
you have an event called lostFocus you can use
button1.LostFocus +=new EventHandler(dataGridView1_LostFocus);
and in the event:
Control lastFocused;
void dataGridView1_LostFocus(object sender, EventArgs e)
{
lastFocused = sender as Control;
}
in that way you can always know what is the Control that was focused previously
now, correct me if i'm wrong, but you do it for the SendKeys.Send("1"); to know which textBox need to receive the number. for that you can use GotFocus event and register only the textBoxs to it.
you can also do what windows is doing and use just one textbox like here:
if it's fits your needs
What about using this with the parameter forward = false?
Control.SelectNextControl Method
You'd probably call it on your "custom Number Keypad control".
I would like to use the drop functionality of the WebBrowser control in C#. Unfortunately it doesn't work although I set the AllowWebBrowserDrop property to true.
For testing I wrote this little programm with just a textbox and a webbrowser control:
public Form1()
{
InitializeComponent();
webBrowser1.AllowWebBrowserDrop = true;
textBox1.Text = "http://www.google.com";
}
private void textBox1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
DoDragDrop(textBox1.Text, DragDropEffects.Link);
}
private void webBrowser1_Navigating(object sender, WebBrowserNavigatingEventArgs e)
{
MessageBox.Show(e.Url.AbsoluteUri);
}
The DoDragDrop method gets executed correctly, but I never see the MessageBox appearing when dropping the string from the TextBox over the WebControl. Since the WebControl doesn't offer the usual drag & drop events I'm lost.
What do I have to do to make the url drop to the WebBrowser control work?
Use the following approach to initiate FileDrop dragging:
DataObject dObj = new DataObject();
var paths = new System.Collections.Specialized.StringCollection();
paths.Add(textBox1.Text);
dObj.SetFileDropList(paths);
textBox1.DoDragDrop(dObj, DragDropEffects.Link);
Is there a way to allow Drag and Drop anywhere in a form full of controls?
The idea is to allow user to drag a file anywhere in a form in order to "load" it. I will not need any other DragDrop behavior but this.
By setting AllowDrop=True to the form only, I get DragEnter events but not DragDrop ones.
An idea would be to make a topmost panel visible on DragEnter and handle DragDrop events there, but I wonder if I miss something obvious here since I have little experience in the field.
Another Idea would be to iterate through all controls and subscribe to Drag-related events. I really don't like this approach, though.
Sure, iterating the controls will work, it doesn't take much code:
public Form1() {
InitializeComponent();
WireDragDrop(this.Controls);
}
private void WireDragDrop(Control.ControlCollection ctls) {
foreach (Control ctl in ctls) {
ctl.AllowDrop = true;
ctl.DragEnter += ctl_DragEnter;
ctl.DragDrop += ctl_DragDrop;
WireDragDrop(ctl.Controls);
}
}
void ctl_DragDrop(object sender, DragEventArgs e) {
// etc..
}
void ctl_DragEnter(object sender, DragEventArgs e) {
// etc..
}
If you still don't like the approach then use a recognizable single drop target that the user will always hit. Could be as simple as a label that says "Drop here".
I'm not sure what kinds of control you have on your form. But I've tested with a Button, a GroupBox, a PictureBox and a TextBox. All these controls have AllowDrop = false by default. And I can drag-n-drop something from outside onto the form OK. The DragDrop is fired OK. Everything is OK. What is actually your problem? I guess your controls have AllowDrop = true.
In the case the DragDrop event is not fired (which I think only happens if the target is one of your Control with AllowDrop = true). I think the following may work. But if the target is one of your Control with AllowDrop = true, the effect icon is gone away.
public Form1(){
InitializeComponents();
t.Interval = 1;
t.Tick += Tick;
}
IDataObject data;
Timer t = new Timer();
int i = 0;
private void Tick(object sender, EventArgs e)
{
Text = (i++).ToString();
if (ClientRectangle.Contains(PointToClient(new Point(MousePosition.X, MousePosition.Y))) && MouseButtons == MouseButtons.None)
{
t.Stop();
if (data != null)
{
//Process data here
//-----------------
data = null;
}
}
else if (MouseButtons == MouseButtons.None)
{
data = null;
t.Stop();
}
}
private void Form1_DragEnter(object sender, DragEventArgs e)
{
e.Effect = e.AllowedEffect;
if (data == null)
{
data = e.Data;
t.Start();
}
}
And I think you may have to use the loop through all the Controls to add appropriate event handlers. There is no other better way.
In the Drop event.
string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
foreach (string file in files) Console.WriteLine(file);
In the DragEnter event.
if (e.Data.GetDataPresent(DataFormats.FileDrop)) e.Effects = DragDropEffects.Copy;