RichTextBox blocks DragDrop event - c#

I have DragDrop and DragEnter events on my SplitContainer.Panel:
splitContainer.Panel.DragDrop += new System.Windows.Forms.DragEventHandler(this.splitContainerPanelDragDrop);
splitContainer.Panel.DragEnter += new System.Windows.Forms.DragEventHandler(this.splitContainerPanelDragEnter);
It works perfect with every control inside SplitContainer.Panel except RichTextBox controls.
How it looks like:
So DragDrop/DragEnter works perfectly in every control inside SplitContainer except controls which is marked yellow color.
What I tried:
1) Set
RichTextBox.AllowDrop = false;
So I even DragEnter is unavailable with "action is not allowed" cursor.
2) Set
RichTextBox.AllowDrop = true;
After this cursor is ok, but it doesnt work because expects additional DragEventHandler in other case it doesnt work.
3) Set
RichTextBox.EnableAutoDragDrop=false;
RichTextBox.AllowDrop=true;
Same result as 2) variant.
I dont want to set DragDrop/DragEnter event for every RichTextBox inside SplitContainer because inside FlowLayoutPanel they are created dynamically.
The question is: is there any method like e.PreventDefault analog in C#? Or what can I do except setting events for every RichTextBox to make it work?

This worked for me
I created 2 custom controls
Custom SplitControl
public partial class SplitControlCustom : SplitContainer
{
public SplitControlCustom()
{
InitializeComponent();
}
public void ForceDrageDrop(DragEventArgs eventArgs)
{
OnDragDrop(eventArgs);
}
public void ForceDragEnter(DragEventArgs eventArgs)
{
OnDragEnter(eventArgs);
}
}
Custom RichTextBox
public partial class RichTextBoxCustom : RichTextBox
{
public RichTextBoxCustom()
{
InitializeComponent();
this.AllowDrop = true;
}
protected override void OnDragEnter(DragEventArgs drgevent)
{
SplitControlCustom parentSplitControl = Parent.Parent as SplitControlCustom;
if (parentSplitControl != null)
{
parentSplitControl.ForceDragEnter(drgevent);
}
}
protected override void OnDragDrop(DragEventArgs drgevent)
{
SplitControlCustom parentSplitControl = Parent.Parent as SplitControlCustom;
if (parentSplitControl != null)
{
parentSplitControl.ForceDrageDrop(drgevent);
}
}
}
Please let me know if it worked

I don't see how you can make this work directly. But then, since you are already willing to add a few lines of code while generating the controls, why not add the necessary events via a few lines of Lambda..:
Let's assume you have just created a RichTextBox and are ready to add it to some Controls collection..:
RichTextBox richTextBox = new RichTextBox ();
...
richTextBox.AllowDrop = true;
richTextBox.DragEnter += (ss, ee) => { ee.Effect = DragDropEffects.Copy; };
richTextBox.DragOver += (ss, ee) => { ee.Effect = DragDropEffects.Copy; };
richTextBox.DragDrop += (ss, ee)
=> { splitContainer.Panel_DragDrop(splitContainer.Panel, ee); };
The first two lambdas set the effect to copy without any checks; of course you will want to add those and pick the appropriate effect.
The third lambda passes the DragEventArgs on the the DragDrop event of the containing panel, so now the RTB is actually 'D&D-through' ..

Just create a custom RichTextBox and override it's DragDrop Events.
public class CustomRichTextBox : RichTextBox
{
#region Methods
#region Overrides
protected override void OnDragEnter(DragEventArgs e)
{
// base.OnDragEnter(e);
}
protected override void OnDragOver(DragEventArgs e)
{
// base.OnDragOver(e);
}
protected override void OnDragLeave(DragEventArgs e)
{
// base.OnDragLeave(e);
}
protected override void OnDrop(DragEventArgs e)
{
// base.OnDrop(e);
}
#endregion
#endregion
}
For some reason RichTextBoxes seem to handle all DragDrop events by default.
In WPF the events will propagate till it gets to the control that expects these events. I'm not sure about WinForms though.

This is what resolved this issue for me.
I had these two events defined, which should have been good enough
MyRichTextBox.DragEnter += MyRichTextBox_DragEnter;
MyRichTextBox.DragDrop += MyRichTextBox_DragDrop;
I found that this one is also apparently needed when using a RichTextBox embedded in
certain controls.
MyRichTextBox.DragOver += MyRichTextBox_DragOver;
private void MyRichTextBox_DragOver(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Copy;
}

Related

Is it possible to override click event for all my textboxs?

I want when the project is starting to create a custom event for every click event inside my textbox.
Then when a new textbox will be created, automatically use this click event.
I don't want to create a custom control for this. I want to assign it once from a method.
Or if it is possible to create a default constructor for all my elements without creating a custom control.
For example, I don't want to create this. Cause I need to replace all my controls
using System;
using System.ComponentModel;
using System.Windows.Forms;
namespace DXApplication1
{
[ToolboxItem(true)]
public class Class1 : TextBox
{
public Class1()
{
this.Click += Class1_Click;
}
private void Class1_Click(object sender, EventArgs e)
{
Console.WriteLine("Click Event");
}
}
}
I have 1000 textboxes on my project. I don't want to add in each onclick method
Is there any way to add a click event to all my textboxes in the project?
I want to add just one line of code to the program. cs. Is it possible?
I'd suggest that you simple traverse all of the controls on your form after you have placed them and then attach the event.
Try something like this:
IEnumerable<TextBox> AllTextBoxes(ScrollableControl #this)
{
foreach (Control control in #this.Controls)
{
if (control is ScrollableControl sc)
{
foreach (TextBox tb1 in AllTextBoxes(sc))
{
yield return tb1;
}
}
if (control is TextBox tb2)
{
yield return tb2;
}
}
}
foreach (var tb in AllTextBoxes(this))
{
tb.Click += (_, _) => MessageBox.Show("Hello");
}
If you derive your control from an existing control you can override the OnClick method instead of subscribing to the event.
public class TextBoxEx: TextBox
{
public TextBoxEx()
{
}
protected override void OnClick(EventArgs e)
{
Console.WriteLine("Click Event");
base.OnClick(e);
}
}
Then you can replace the type TextBox by TextBoxEx (with find/replace) in the form's .designer.cs file without having to delete and re-insert your textboxes.
Once you have compiled this code, the new textbox appears in the Toolbox window and you can drag and drop it to your form, just as with the standard textbox.
If you have a textBox1_Click method in your form, you can select this same method as event handler for all your textboxes in the properties window: How to: Connect Multiple Events to a Single Event Handler in Windows Forms
As I understand it, you have three requirements:
When the project starts, attach a click event to all TextBox instances already created in the Form designer.
When a new text box is created (programmatically or by user interaction) attach the click event to the new textbox automatically.
Implement this functionality without making a custom class.
This answer shows one way to meet these three objectives.
Utility
First, make a utility that can iterate all of the controls in the Form, but also all the controls of its child controls.
void IterateControlTree(Action<Control> action, Control control = null)
{
if (control == null)
{
control = this;
}
action(control);
foreach (Control child in control.Controls)
{
IterateControlTree(action, child);
}
}
Attach handler to all existing TextBox controls
Using this utility, initialize any textboxes added in design mode to route to the click handler.
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
IterateControlTree((control) =>
{
// Attach click handlers to the textboxes
// already added in the Forms designer.
if (control is TextBoxBase)
{
control.Click += onAnyClickTextBox;
}
});
.
.
.
}
// Show the name of the clicked text box.
private void onAnyClickTextBox(object sender, EventArgs e)
{
if(sender is Control control)
{
textBox1.Text = $"Clicked: {control.Name}";
}
}
}
Attach handler automatically to new TextBox controls
Iterate a second time to attach the ControlAdded event to every control. This way, new TextBox instances can be detected in order to attach the Click event.
public MainForm()
{
.
.
.
IterateControlTree((control) =>
{
control.ControlAdded += (sender, e) =>
{
// Get notified when any control collection is changed.
if(e.Control is TextBoxBase textbox)
{
textbox.Click += onAnyClickTextBox;
}
};
});
}
Testing
// FOR TESTING PURPOSES
int _id = 1;
private void onClickNew(object sender, EventArgs e)
{
flowLayoutPanel.Controls.Add(new TextBox
{
Name = $"dynamicTextBox{_id}",
PlaceholderText = $"TextBox{_id}",
});
_id++;
}

C# override event with custom eventargs

I need a custom NumericUpDown where the event ValueChanged should pass CancelEventArgs instead of EventArgs as I want to be able to cancel the editing when certain conditions are verified (e.g. I have two NumericUpDown that must have always different values). If I try to override OnValueChanged I obviously get an error.
protected override void OnValueChanged(CancelEventArgs e)
{
if (e.Cancel)
return;
else
{
EventArgs args = (EventArgs)e;
base.OnValueChanged(args);
}
}
Is there a way to do this?
I would propose to change a little bit your implementation of the cancel behavior, instead of trying to pass the information of Cancellation through the event arguments, you can query it on demand by introducing a new event to your custom component. Here is a simple example:
class CustomNumericUpDown : NumericUpDown
{
protected override void OnValueChanged(EventArgs e)
{
if (QueryCancelValueChanging != null && QueryCancelValueChanging())
return;
else
{
EventArgs args = (EventArgs)e;
base.OnValueChanged(args);
}
}
public event Func<bool> QueryCancelValueChanging;
}
In this situation, the host of your component can subscribe to the new event in order to decide to cancel or not the "ValueChanged" event.
EDIT:
Usage example:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
CustomNumericUpDown nudTest = new CustomNumericUpDown();
nudTest.QueryCancelValueChanging += NudTest_QueryCancelValueChanging;
}
private bool NudTest_QueryCancelValueChanging()
{
return true;/* Replace by custom condition here*/
}
}
Perhaps you need to learn how to create and manage custom events if you have never done it before, it should be easy to find tutorials on this topic on the web (like this one )

how to call Resize Event in C#

I'm trying to create new Button with custom event. It's new for me. I'm trying to call "Resize". I wanna create "switch" like in android.
I'm trying to do this like other existing controls. I've been doing this for 2 days and i still have nothing. I belive that you will able to help me :)
Here is my code:
public abstract class SwitchBase : Control
{
private Button first;
private Button second;
public SwitchBase()
{
InitializeMySwitch();
}
private void InitializeMySwitch()
{
Controls.Add(first = new Button());
Controls.Add(second = new Button());
//first
first.Text = "first";
//second
second.Text = "second";
second.Location = new System.Drawing.Point(first.Location.X + first.Width, first.Location.Y);
}
public delegate void ChangedEventHandler(object source, EventArgs args);
public event ChangedEventHandler Changed;
protected virtual void OnSwitchChanged()
{
if (Changed != null)
Changed(this, EventArgs.Empty);
}
public delegate void ResizeEventHandler(object source, EventArgs args);
public event ResizeEventHandler Resize;
protected virtual void OnResize()
{
Resize(this, EventArgs.Empty);
}
}
public class Switch : SwitchBase
{
public Switch()
{
}
protected override void OnSwitchChanged()
{
base.OnSwitchChanged();
}
protected override void OnResize()
{
base.OnResize();
}
}
In another button I change the size of my switch
From reading your code, I gather that by "call Resize" you mean to raise the event. What you are doing is correct... although it should be noted that by the default event implementation, it will be null if there are no subscribers...
In fact, another thread could be unsubscribing behind your back. Because of that the advice is to take a copy.
You can do that as follows:
var resize = Resize;
if (resize != null)
{
resize(this, EventArgs.Empty)
}
It should be noted that the above code will call the subscribers to the event, but will not cause the cotrol to resize. If what you want is to change the size of your control, then do that:
this.Size = new Size(400, 200);
Or:
this.Width = 400;
this.Height = 200;
Note: I don't know what Control class you are using. In particular, if it were System.Windows.Forms.Control it already has a Resize event, and thus you won't be defining your own. Chances are you are using a Control class that doesn't even have Size or Width and Height.
Edit: System.Web.UI.Control doesn't have Resize, nor Size or Width and Height. But System.Windows.Controls.Control has Width and Height even thought it doesn't have Resize.

generate OnCheckedChanged for custom checkbox

I have a custom checkbox control that inherited from System.Windows.Forms.Control
and it hasn't CheckedChanged event. I want to implement CheckedChange same as dot net native CheckBox. How can I do it well ?
You are inheriting fromn Control, not CheckBox, so the solution is similar to the one proposed by Frigik, but it's not exactly that one.
First of all you have to define the event in your class, i.e.:
public event EventHandler CheckedChanged;
In this way every developer using your control can subscribe/unsubscribe to the event. This is not enough, since the event will never be triggered. To do so, you have to define a method to trigger it, and the call this method whenever the state of your control changes:
private void RaiseCheckedChanged()
{
if (CheckedChanged!= null)
CheckedChanged(this, EventArgs.Empty);
}
Where this method will be called depends on the structure of your control. For instance if you have a property Checked, you could call the method in its setter:
public bool Checked
{
get { return _checked; }
set
{
_checked = value;
RaiseCheckedChanged();
}
}
Try this code :
CheckBox chkList1 = new CheckBox();
chkList1.CheckedChanged += new EventHandler(CheckBox_CheckedChanged);
protected void CheckBox_CheckedChanged(object sender, EventArgs e)
{
// Do your stuff
}
Try this:
public class YourCheckBox:CheckBox
{
public event EventHandler<EventArgs> OnCheckedChangedCustom;
protected override void OnCheckedChanged(EventArgs e)
{
if (OnCheckedChangedCustom!=null)
{
OnCheckedChangedCustom(this, EventArgs.Empty);
}
base.OnCheckedChanged(e);
}
}

Changing the properties of the active control automatically

Please consider that im a newcomer to c#. After scanning about 700 posts i decided to post one more question:
On my windows form (c#) I have some controls including textboxes, checkboxes and so on.
I want to change the backcolor whenever the controls become active.
I know i could raise 'enter' and 'leave' events for each control to change the corresponding properties but there should be another way.
Simply hook Enter and Leave events - toggling the color in each. Save the last color saved in OnEnter to use in OnLeave
public Form1()
{
InitializeComponent();
var lastColorSaved = Color.Empty;
foreach(Control child in this.Controls)
{
child.Enter += (s, e) =>
{
var control = (Control)s;
lastColorSaved = control.BackColor;
control.BackColor = Color.Red;
};
child.Leave += (s, e) =>
{
((Control)s).BackColor = lastColorSaved;
};
}
}
You customize control classes just like you customize any class, you derive your own class and override the virtual methods. Arbitrarily:
using System;
using System.Drawing;
using System.Windows.Forms;
class MyTextBox : TextBox {
protected override void OnEnter(EventArgs e) {
prevColor = this.BackColor;
this.BackColor = Color.Cornsilk;
base.OnEnter(e);
}
protected override void OnLeave(EventArgs e) {
this.BackColor = prevColor;
base.OnLeave(e);
}
private Color prevColor;
}
Now any MyTextBox you drop on the form will have this behavior without having to implement events. Although there's certainly nothing wrong with using events.
Create a class (eg. ControlColorizer) and in its constructor pass:
1) The backcolor for the 'active control' and save to a internal Color variable
2) a variable length Control array
In the contructor add the same event handler for OnEnter and OnLeave on each control
In the OnEnter event set the backcolor
In the OnLeave event set the standard background color
The advantage is all in the use of the class:
1) Declare a global instance in your form class
2) Initialize in the form contructor after the InitializeComponent.
3) Forget everything else. No other code required
So let me explain everything with code:
This will go in a file called ControlColorizer.cs
public class ControlColorizer
{
private Color _setBColor = SystemColors.Window;
public ControlColor(Color bkg, params Control[] ctls)
{
_setBColor = bkg;
foreach (Control o in ctls)
{
o.Enter += new EventHandler(o_Enter);
o.Leave += new EventHandler(o_Leave);
}
}
private void o_Enter(object sender, EventArgs e)
{
if (sender is Control)
{
Control c = (Control)sender;
c.BackColor = _setBColor;
}
}
private void o_Leave(object sender, EventArgs e)
{
Control c = sender as Control;
c.BackColor = SystemColors.Window;
}
Now, in every form contructor where you need the functionality you have this
ControlColirizer _ccz;
public Form1()
{
InitializeComponent();
// Create an instance of ControlColorizer, pass the background color
// the list of Controls and that's all
_ccz = new ControlColorizer(Color.LightYellow, this.TextBox1,
this.TextBox2, this.TextBox3, this.TextBox4);
}

Categories