Remove single event handler from a user control - c#

Say I have two user controls and I want to remove an event handler from one instance of the control.
To illustrate I've just made it a button as user control:
public partial class SuperButton : UserControl
{
public SuperButton()
{
InitializeComponent();
}
private void button1_MouseEnter(object sender, EventArgs e)
{
button1.BackColor = Color.CadetBlue;
}
private void button1_MouseLeave(object sender, EventArgs e)
{
button1.BackColor = Color.Gainsboro;
}
}
I've added two super buttons to the form and I want to disable the MouseEnter event firing for SuperButton2.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
superButton2.RemoveEvents<SuperButton>("EventMouseEnter");
}
}
public static class EventExtension
{
public static void RemoveEvents<T>(this Control target, string Event)
{
FieldInfo f1 = typeof(Control).GetField(Event, BindingFlags.Static | BindingFlags.NonPublic);
object obj = f1.GetValue(target.CastTo<T>());
PropertyInfo pi = target.CastTo<T>().GetType().GetProperty("Events", BindingFlags.NonPublic | BindingFlags.Instance);
EventHandlerList list = (EventHandlerList)pi.GetValue(target.CastTo<T>(), null);
list.RemoveHandler(obj, list[obj]);
}
public static T CastTo<T>(this object objectToCast)
{
return (T)objectToCast;
}
}
The code runs but it doesn't work - the MouseEnter and Leave events still fire. I'm looking to do something like this:
superButton2.MouseEnter -= xyz.MouseEnter;
Update: Read this comments questions...

In your case, you don't need to remove all event handlers at once, just the specific one you're interested in. Use -= to remove a handler in the same way you use += to add one:
button1.MouseEnter -= button1_MouseEnter;

Why not just set superButton2.MouseEnter = null;? That should do the trick until somewhere MouseEnter is assigned a value.
Just for an update, another way to handle it, and perfectly legal :)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
namespace TestControls
{
class SimpleButton:Button
{
public bool IgnoreMouseEnter { get; set; }
public SimpleButton()
{
this.IgnoreMouseEnter = false;
}
protected override void OnMouseEnter(EventArgs e)
{
Debug.Print("this.IgnoreMouseEnter = {0}", this.IgnoreMouseEnter);
if (this.IgnoreMouseEnter == false)
{
base.OnMouseEnter(e);
}
}
}
}

Related

How do I add and subtract event handlers inside a derived abstract class?

Short version
In my abstract class MyCbo_Abstract (derived from ComboBox class), I want to create a custom property that when set will subtract all the control's event handlers, set the base property value, then re-add all the control's event handlers.
What I have so far
I have a concrete ComboBox class derived from an abstract ComboBox class derived from Microsoft's ComboBox class.
public abstract class MyCbo_Abstract : ComboBox
{
public MyCbo_Abstract() : base()
{
}
}
public partial class MyCboFooList : MyCbo_Abstract
{
public MyCboFooList() : base()
{
}
}
My main Form class subscribes to certain base ComboBox events.
Note: The designer has: this.myCboFooList = new MyCboFooList();
public partial class FormMain : Form
{
public FormMain()
{
myCboFooList.SelectedIndexChanged += myCboFooList_SelectedIndexChanged;
}
private void myCboFooList_SelectedIndexChanged(object sender, EventArgs e)
{
// do stuff
}
}
There are times when I want to suppress the invocation of defined event handlers, e.g., when I programmatically set a ComboBox object's SelectedIndex property.
Instead of having to remember to write the code to subtract and re-add event handlers each time I want to modify the SelectedIndex property and suppress its events, I want to create a custom property SelectedIndex_NoEvents that when set will subtract all the control's event handlers, set the base property value SelectedIndex, then re-add all the control's event handlers.
The problem
My problem is that I don't know how to iterate over a EventHandlerList because it has no GetEnumerator. And, in looking at the list in the debugger, saveEventHandlerList is a weird chained thing that I can't figure out how to otherwise traverse.
public abstract class MyCbo_Abstract : ComboBox
{
int selectedIndex_NoEvents;
public int SelectedIndex_NoEvents
{
get
{
return base.SelectedIndex;
}
set
{
EventHandlerList saveEventHandlerList = new EventHandlerList();
saveEventHandlerList = Events;
//foreach won't work - no GetEnumerator available. Can't use for loop - no Count poprerty
foreach (EventHandler eventHandler in saveEventHandlerList)
{
SelectedIndexChanged -= eventHandler;
}
base.SelectedIndex = value;
//foreach won't work - no GetEnumerator available. Can't use for loop - no Count poprerty
foreach (EventHandler eventHandler in saveEventHandlerList)
{
SelectedIndexChanged += eventHandler;
}
saveEventHandlerList = null;
}
}
//Probably don't need this
public override int SelectedIndex
{
get
{
return base.SelectedIndex;
}
set
{
base.SelectedIndex = value;
}
}
public DRT_ComboBox_Abstract() : base()
{
}
}
Before giving you the solution that I created, let me say that this feels extremely hacky. I urge you to seriously think about another solution. There may be all kinds of crazy edge cases where this code breaks down, I haven't thoroughly tested it beyond the example code shown below.
Add the following utility class:
public class SuspendedEvents
{
private Dictionary<FieldInfo, Delegate> handlers = new Dictionary<System.Reflection.FieldInfo, System.Delegate>();
private object source;
public SuspendedEvents(object obj)
{
source = obj;
var fields = obj.GetType().GetFields(BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
foreach (var fieldInfo in fields.Where(fi => fi.FieldType.IsSubclassOf(typeof(Delegate))))
{
var d = (Delegate)fieldInfo.GetValue(obj);
handlers.Add(fieldInfo, (Delegate)d.Clone());
fieldInfo.SetValue(obj, null);
}
}
public void Restore()
{
foreach (var storedHandler in handlers)
{
storedHandler.Key.SetValue(source, storedHandler.Value);
}
}
}
You can use it like this:
var events = new SuspendedEvents(obj); //all event handlers on obj are now detached
events.Restore(); // event handlers on obj are now restored.
I used the following test setup:
void Main()
{
var obj = new TestObject();
obj.Event1 += (sender, e) => Handler("Event 1");
obj.Event1 += (sender, e) => Handler("Event 1");
obj.Event2 += (sender, e) => Handler("Event 2");
obj.Event2 += (sender, e) => Handler("Event 2");
obj.Event3 += (sender, e) => Handler("Event 3");
obj.Event3 += (sender, e) => Handler("Event 3");
Debug.WriteLine("Prove events are attached");
obj.RaiseEvents();
var events = new SuspendedEvents(obj);
Debug.WriteLine("Prove events are detached");
obj.RaiseEvents();
events.Restore();
Debug.WriteLine("Prove events are reattached");
obj.RaiseEvents();
}
public void Handler(string message)
{
Debug.WriteLine(message);
}
public class TestObject
{
public event EventHandler<EventArgs> Event1;
public event EventHandler<EventArgs> Event2;
public event EventHandler<EventArgs> Event3;
public void RaiseEvents()
{
Event1?.Invoke(this, EventArgs.Empty);
Event2?.Invoke(this, EventArgs.Empty);
Event3?.Invoke(this, EventArgs.Empty);
}
}
It produces the following output:
Prove events are attached
Event 1
Event 1
Event 2
Event 2
Event 3
Event 3
Prove events are detached
Prove events are reattached
Event 1
Event 1
Event 2
Event 2
Event 3
Event 3
There is no way to easily disable event firing of WinForm controls exposed in the .Net framework. However, the Winform controls follow a standard design pattern for events in that all event signatures are based on the EventHandler Delegate and the registered event handlers are stored in an EventHandlerList that is defined in the Control Class. This list is stored in a field (variable) named "events" and is only publicly exposed via the read-only property Events.
The class presented below uses reflection to temporarily assign null to the events field effectively removing all event handlers registered for the Control.
While it may be an abuse of the pattern, the class implements the IDisposable Interface to restore the events field on disposal of the class instance. The reason for this is to facilitate the use of the using block to wrap the class usage.
public class ControlEventSuspender : IDisposable
{
private const string eventsFieldName = "events";
private const string headFieldName = "head";
private static System.Reflection.FieldInfo eventsFieldInfo;
private static System.Reflection.FieldInfo headFieldInfo;
private System.Windows.Forms.Control target;
private object eventHandlerList;
private bool disposedValue;
static ControlEventSuspender()
{
Type compType = typeof(System.ComponentModel.Component);
eventsFieldInfo = compType.GetField(eventsFieldName, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
headFieldInfo = typeof(System.ComponentModel.EventHandlerList).GetField(headFieldName, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
}
private static bool FieldInfosAquired()
{
if (eventsFieldInfo == null)
{
throw new Exception($"{typeof(ControlEventSuspender).Name} could not find the field '{ControlEventSuspender.eventsFieldName}' on type Component.");
}
if (headFieldInfo == null)
{
throw new Exception($"{typeof(ControlEventSuspender).Name} could not find the field '{ControlEventSuspender.headFieldName}' on type System.ComponentModel.EventHandlerList.");
}
return true;
}
private ControlEventSuspender(System.Windows.Forms.Control target) // Force using the the Suspend method to create an instance
{
this.target = target;
this.eventHandlerList = eventsFieldInfo.GetValue(target); // backup event hander list
eventsFieldInfo.SetValue(target, null); // clear event handler list
}
public static ControlEventSuspender Suspend(System.Windows.Forms.Control target)
{
ControlEventSuspender ret = null;
if (FieldInfosAquired() && target != null)
{
ret = new ControlEventSuspender(target);
}
return ret;
}
protected virtual void Dispose(bool disposing)
{
if (!this.disposedValue)
{
if (disposing)
{
if (this.target != null)
{
RestoreEventList();
}
}
}
this.disposedValue = true;
}
public void Dispose()
{
Dispose(true);
}
private void RestoreEventList()
{
object o = eventsFieldInfo.GetValue(target);
if (o != null && headFieldInfo.GetValue(o) != null)
{
throw new Exception($"Events on {target.GetType().Name} (local name: {target.Name}) added while event handling suspended.");
}
else
{
eventsFieldInfo.SetValue(target, eventHandlerList);
eventHandlerList = null;
target = null;
}
}
}
Example usage in the button1_Click method:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
using (ControlEventSuspender.Suspend(comboBox1))
{
comboBox1.SelectedIndex = 3; // SelectedIndexChanged does not fire
}
}
private void button2_Click(object sender, EventArgs e)
{
comboBox1.SelectedIndex = -1; // clear selection, SelectedIndexChanged fires
}
private void button3_Click(object sender, EventArgs e)
{
comboBox1.SelectedIndex = 3; // SelectedIndexChanged fires
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
Console.WriteLine("index changed fired");
System.Media.SystemSounds.Beep.Play();
}
}
SoapBox Diatribe
Many will say that the use of Reflection to access non-public class members is dirty or some other derogatory term and that it introduces a brittleness to the code as someone may change the underlying code definition such that the code that relies on member names (magic strings) is no longer valid. This is a valid concern, but I view it as no different than code that accesses external databases.
Reflection can be thought of a query of a type (datatable) from an assembly (database) for specific fields (members: fields, properties, events). It is no more brittle than a SQL statement such as Select SomeField From SomeTable Where AnotherField=5. This type of SQL code is prevent in the world and no one thinks twice about writing it, but some external force could easily redefine the database you code relies on an render all the magic string SQL statements invalid as well.
Use of hard coded names is always at risk of being made invalid by change. You have to weigh the risks of moving forward versus the option of being frozen in fear of proceeding because someone wants to sound authoritative (typically a parroting of other such individuals) and criticize you for implementing a solution that solves the current problem.
I was hoping to write code that would programatically locate all event handler method names created using controlObject.Event += EventHandlerMethodName, but as you see in the other answers, code to do this is complicated, limited, and perhaps not able to work in all cases
This is what I came up with. It satisfies my desire to consolidate the code that subtracts and re-adds event handler method names into my abstract class, but at the expense of having to write code to store and manage event handler method names and having to write code for each control property where I want to suppress the event handler, modify the property value, and finally re-add the event handler.
public abstract class MyCbo_Abstract : ComboBox
{
// create an event handler property for each event the app has custom code for
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
private EventHandler evSelectedValueChanged;
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public EventHandler EvSelectedValueChanged { get => evSelectedValueChanged; set => evSelectedValueChanged = value; }
public MyCbo_Abstract() : base()
{
}
// Create a property that parallels the one that would normally be set in the main body of the program
public object _DataSource_NoEvents
{
get
{
return base.DataSource;
}
set
{
SelectedValueChanged -= EvSelectedValueChanged;
if (value == null)
{
base.DataSource = null;
SelectedValueChanged += EvSelectedValueChanged;
return;
}
string valueTypeName = value.GetType().Name;
if (valueTypeName == "Int32")
{
base.DataSource = null;
SelectedValueChanged += EvSelectedValueChanged;
return;
}
//assume StringCollection
base.DataSource = value;
SelectedValueChanged += EvSelectedValueChanged;
return;
}
}
}
public partial class MyCboFooList : MyCbo_Abstract
{
public MyCboFooList() : base()
{
}
}
Designer has
this.myCboFooList = new MyCboFooList();
Main form code
public partial class FormMain : Form
{
public FormMain()
{
myCboFooList.SelectedValueChanged += OnMyCboFooList_SelectedValueChanged;
myCboFooList.EvSelectedValueChanged = OnMyCboFooList_SelectedValueChanged;
}
private void OnMyCboFooList_SelectedValueChanged(object sender, EventArgs e)
{
// do stuff
}
}
And now, if I want to set a property and suppress event(s), I can write something like the following and not have to remember to re-add the event handler method name
myCboFooList._DataSource_NoEvents = null;

Unable to register click event from composite control to parent form

What I am attempting to do is create a complex control that has a picture box, track slider and numeric up down controls. In the parent form, when the user clicks on an image, then this composite control appears and the background color is then sent to it and the image in the control is then set with that background color. Then if the user clicks on the image on the composite control, the parent form is then notified of the click event and then subsequently removes that specific composite control from the parent form.
Composite Control code
using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
namespace ctlClusterControlLib
{
public partial class UserControl1 : UserControl
{
private Color colImageBackground;
private int intThreadCount;
private PictureBox pictureBoxControl; // Compiler informs me that this is never assigned to and will always have its default value null.
private TrackBar trackBar; // Compiler informs me that this is never assigned to and will always have its default value null.
private NumericUpDown numericUpDown; // Compiler informs me that this is never assigned to and will always have its default value null.
private string strImageToolTip1;
private string strImageToolTip2;
private static object EventSubmitKey = new object();
public UserControl1()
{
InitializeComponent();
}
public Color ImageBackground
{
get { return colImageBackground; }
set { colImageBackground = value; Invalidate(); }
}
public int ThreadCount
{
get { return intThreadCount; }
set { intThreadCount = value; }
}
[
Category("Action"),
Description("Raised when the user clicks on the image.")
]
public event EventHandler PictureClick
{
add { Events.AddHandler(EventSubmitKey, value); }
remove { Events.RemoveHandler(EventSubmitKey, value); }
}
public event EventHandler TrackBarScroll
{
add { trackBar.Scroll += value; }
remove { trackBar.Scroll -= value; }
}
public event EventHandler numericUpDownChange
{
add { numericUpDown.ValueChanged += value; }
remove { numericUpDown.ValueChanged -= value; }
}
public string ImageToolTip1
{
get { return strImageToolTip1; }
set { strImageToolTip1 = value; }
}
public string ImageToolTip2
{
get { return strImageToolTip2; }
set { strImageToolTip2 = value; }
}
private void trackBar1_Scroll(object sender, EventArgs e)
{
numericUpDown1.Value = trackBar1.Value;
}
private void numericUpDown1_ValueChanged(object sender, EventArgs e)
{
trackBar1.Value = Convert.ToInt32(numericUpDown1.Value);
}
protected override void OnPaint(PaintEventArgs pe)
{
base.OnPaint(pe);
Color c = Color.FromArgb(0xFF, colImageBackground);
pictureBox1.BackColor = c;
}
}
}
Parent Form CS relevant section:
private void newPictureBox_Click(object sender, EventArgs e)
{
UserControl1 _UserControl = new UserControl1();
PictureBox _PictureBox = (PictureBox)sender;
string _NewControlClusterName = "_New" + _PictureBox.Name;
_UserControl.Name = _NewControlClusterName;
_UserControl.ThreadCount = 16;
_UserControl.ImageBackground = _PictureBox.BackColor;
_UserControl.Dock = DockStyle.Top;
_UserControl.PictureClick += new EventHandler(ClusterControl_Click);
//_UserControl.TrackBarScroll += new EventHandler(GetTartanCode);
panel3.Controls.Add(_UserControl);
panel3.Controls.SetChildIndex(_UserControl, 0);
}
And I am having intermittent issues with raising the click event to the parent form using this control.
I have tried everything I can find in Google and Stack Overflow with no joy. My questions are this:
Am I even in the right ballpark?
Is this something that needs to be coded in the parent form cs file?
Is this something that needs to be reconfigured in the composite control cs file?
Is this something that needs to be configured in both files?
I believe I have a solution.
What I was not doing was directly assigning the request to the control I wanted to register the event for. Instead I was assigning it to a new control and therefore nothing would happen.
public event EventHandler PictureClick
{
add { pictureBox1.Click += value; }
remove { pictureBox1.Click -= value; }
}
And so far, It works every time.

UITypeEditor is not closing properly

I am using a UserControl with a UITypeEditor. The user control has OK and Cancel buttons that do nothing except display a MessageBox with either OK or Cancel and then hide the user control. But when I click one of the buttons, the PropertyGrid displays an empty box where the UserControl was until I click away. Then the box disappears and the dialog is displayed.
Here is the user control code:
using System;
using System.Windows.Forms;
namespace j2associates.Tools.Winforms.Controls.DesignTimeSupport.SupportingClasses
{
public partial class SimpleTest : UserControl
{
public bool Cancelled { get; set; }
public SimpleTest()
{
InitializeComponent();
}
private void btnOK_Click(object sender, EventArgs e)
{
Cancelled = false;
this.Hide();
}
private void btnCancel_Click(object sender, EventArgs e)
{
Cancelled = true;
this.Hide();
}
}
}
Here is the UITypeEditor code:
using System;
using System.Drawing.Design;
using System.Windows.Forms;
using System.Windows.Forms.Design;
using j2associates.Tools.Winforms.Controls.DesignTimeSupport.SupportingClasses;
namespace j2associates.Tools.Winforms.Controls.DesignTimeSupport.Editors
{
internal class TimeElementsEditor : UITypeEditor // PropertyEditorBase<TimeElementsUserControl>
{
public override UITypeEditorEditStyle GetEditStyle(System.ComponentModel.ITypeDescriptorContext context)
{
return UITypeEditorEditStyle.DropDown;
}
public override object EditValue(System.ComponentModel.ITypeDescriptorContext context, IServiceProvider provider, object value)
{
if (value.GetType() == typeof(j2aTimePicker.TimeElementOptions))
{
var editorService = provider.GetService(typeof(IWindowsFormsEditorService)) as IWindowsFormsEditorService;
if (editorService != null)
{
using (var st = new SimpleTest())
{
editorService.DropDownControl(st);
if (st.Cancelled)
{
MessageBox.Show("Cancel");
}
else
{
MessageBox.Show("OK");
}
editorService.CloseDropDown();
}
}
}
return value;
}
}
}
Any ideas and/or suggestions would be appreciated.
Sigh, it's always easy when you find it.
I needed to pass the IWindowsFormsEditorService in via an overloaded constructor, cache it and then call it's CloseDropdown method in the Button Click events instead of hiding the user control. It now works as expected.
/// <summary>
/// Displays an OK and Cancel button. When one is pressed,
/// the dialog is closed and a message box is displayed.
/// The actual value of the property is unchanged throughout.
/// </summary>
/// <remarks>The ToolboxItem attribute prevents the control from being displayed in the ToolKit.</remarks>
[ToolboxItem(false)]
public partial class SimpleTest : UserControl
{
public bool Cancelled { get; set; }
private IWindowsFormsEditorService m_EditorService;
// Require the use of the desired overloaded constructor.
private SimpleTest()
{
InitializeComponent();
}
internal SimpleTest(IWindowsFormsEditorService editorService)
: this()
{
// Cache the editor service.
m_EditorService = editorService;
}
private void btnOK_Click(object sender, EventArgs e)
{
Cancelled = false;
m_EditorService.CloseDropDown();
}
private void btnCancel_Click(object sender, EventArgs e)
{
Cancelled = true;
m_EditorService.CloseDropDown();
}
}
And here is the modified editor call:
using (var simpleTest = new SimpleTest(editorService))
{
editorService.DropDownControl(simpleTest);
MessageBox.Show(simpleTest.Cancelled ? "Cancelled" : "OK");
}

Display specific properties in the Property grid

When we press the btnSettings, all the user controls properties will be displayed in Property grid. I want display specific properties (only TemperatureValue and TemperatureUnit), is possible? User control code as follows:
using System;
using System.Windows.Forms;
namespace Temperature
{
public partial class temperatureUc : UserControl
{
public enum temperatureUnit
{
Celsius, // default
Delisle, // °De = (100 − °C) * 3⁄2
Fahrenheit, // °F = °C * 9⁄5 + 32
Kelvin, // °K = °C + 273.15
Newton, // °N = °C * 33⁄100
Rankine, // °R = (°C + 273.15) * 9⁄5
Réaumur, // °Ré = °C * 4⁄5
Rømer // °Rø = °C * 21⁄40 + 7.5
}
public temperatureUc()
{
InitializeComponent();
this.cboTemperatureUnit.DataSource = Enum.GetValues(typeof(temperatureUnit));
}
#region "Event"
public delegate void SettingsStateEventHandler(object sender, EventArgs e);
public event SettingsStateEventHandler settingsStateChanged;
private void OnSettingsChanged(object sender, EventArgs e)
{
if (this.settingsStateChanged != null)
this.settingsStateChanged(sender, e);
}
#endregion
#region "Properties"
private Single _TemperatureValue;
public Single TemperatureValue
{
get
{
return this._TemperatureValue;
}
set
{
if (value.GetType() == typeof(Single))
{
_TemperatureValue = value;
this.txtTemperatureValue.Text = _TemperatureValue.ToString();
}
}
}
private temperatureUnit _TemperatureUnit;
public temperatureUnit TemperatureUnit
{
get
{
return this._TemperatureUnit;
}
set
{
if (value.GetType() == typeof(temperatureUnit))
{
_TemperatureUnit = value;
this.cboTemperatureUnit.Text = _TemperatureUnit.ToString();
}
}
}
#endregion
private void btnSettings_Click(object sender, EventArgs e)
{
this.OnSettingsChanged(sender, e);
}
}
}
User control above code will be called from code bellow:
using System;
using System.Windows.Forms;
using Temperature;
using System.Diagnostics;
using System.Drawing;
namespace TemperatureImplements
{
public partial class Form1 : Form
{
private PropertyGrid pGrid = new PropertyGrid();
public Form1()
{
InitializeComponent();
this.temperatureUc1.settingsStateChanged += new temperatureUc.SettingsStateEventHandler(temperatureUc1_settingsStateChanged);
}
void temperatureUc1_settingsStateChanged(object sender, EventArgs e)
{
pGrid.Size = new Size(300, 500);
pGrid.Location = new Point(300,10);
pGrid.SelectedObject = temperatureUc1;
this.Controls.Add(pGrid);
}
}
}
Picture as follows:
There is a way. This article has a section called "Customizing the PropertyGrid Control" that explains how to do it http://msdn.microsoft.com/en-us/library/aa302326.aspx#usingpropgrid_topic5
Basically you just want to define the AppSettings class to only include TemperatureUnit andTemeratureValue`.
AppSettings appset = new AppSettings();
MyPropertyGrid.SelectedObject = appset;
Define AppSettings as follows;
[DefaultPropertyAttribute("SaveOnClose")]
public class AppSettings{
private bool saveOnClose = true;
private string tempUnit;
private int tempValue;
[CategoryAttribute("Global Settings"),
ReadOnlyAttribute(false),
DefaultValueAttribute("Celsius")]
public string TemperatureUnit
{
get { return tempUnit; }
set { tempUnit = value; }
}
[CategoryAttribute("Global Settings"),
ReadOnlyAttribute(false),
DefaultValueAttribute(0)]
public string TemperatureValue
{
get { return tempValue; }
set { tempValue = value; }
}
}
By the way, I'm changing the category from Misc to Global Settings, don't know if that's what you want but it makes sense when they're the only options. You may have to explicitly declare the other attributes this BrowsableAttribute(false) so they're not displayed but I don't think it's necessary.
There might be a way to hide those properties but I think that's the wrong way to go about it.
Instead of passing the user control itself you should create a model with TemperatureUnit and TemperatureValue. Move your defined events to this model.
Then you need to extend a user control which you pass the model to and listens for these events.
Finally set pGrid.SelectedObject to your model and you'll be good to go.

How to get datetimepicker c# winform checked/unchecked event

There is a check box in the datetimepicker control of winforms .net.
But I could not find the event that is triggered when the check box is checked or unchecked .
Is there a way out?
It does however trigger the value changed event
You´ll have to store the old "checked" value in order to compare to the new one, so you´ll be able to determine if the "checked" state has changed:
bool oldDateChecked = false; //if it's created as not checked
private void dtp_filtro_date_ValueChanged(object sender, EventArgs e)
{
if (this.dtp_filtro_date.Checked != oldDateChecked)
{
oldDateChecked = this.dtp_filtro_date.Checked;
//do your stuff ...
}
}
Run into the same issue. I needed a CheckedChangedEvent on a winforms DateTimePicker control. So with the inspiration of the answers before me I created an inherited User Control named DateTimePicker2, inheriting from DateTimePicker that implements this event. It looks like it works but no guarantees.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace MyNameSpace
{
public partial class DateTimePicker2 : DateTimePicker
{
private bool _checked;
public new bool Checked
{
get
{
return base.Checked;
}
set
{
if (value != base.Checked)
{
base.Checked = value;
_checked = base.Checked;
OnCheckedChanged(new CheckedChangedEventArgs { OldCheckedValue = !value, NewCheckedValue = value });
}
}
}
public event CheckedChangedEventHandler CheckedChanged;
public DateTimePicker2()
{
InitializeComponent();
_checked = Checked;
}
protected virtual void OnCheckedChanged(CheckedChangedEventArgs e)
{
if (CheckedChanged != null) CheckedChanged(this, e);
}
private void DateTimePicker2_ValueChanged(object sender, EventArgs e)
{
if (Checked != _checked)
{
_checked = Checked;
CheckedChangedEventArgs cce = new CheckedChangedEventArgs { OldCheckedValue = !_checked, NewCheckedValue = _checked };
OnCheckedChanged(cce);
}
}
}
public delegate void CheckedChangedEventHandler(object sender, CheckedChangedEventArgs e);
public class CheckedChangedEventArgs : EventArgs
{
public bool OldCheckedValue { get; set; }
public bool NewCheckedValue { get; set; }
}
}
And off-course don't forget to subscribe to the DateTimePicker2_ValueChanged event from the designer.
The reason why I used both a new Checked property (to hide the base.Checked one) and a _checked field to keep truck of the old value, is because
the base.Checked property does not fire the ValueChanged event when changed programmatically and therefore needed a new property that could do that.
the this.Checked new property does not fire the ValueChanged event when changed from the UI and therefore needed a flag that would track the base.Checked property.
Basically a combination of both approaches was needed.
I hope this helps.
I know this is super old but this could help someone.
You can capture DataTimePicker.MouseUp event
private void dateTimePicker1_MouseUp(object sender, MouseEventArgs e)
{
if (((DateTimePicker)sender).Checked)
{
//Do whatever you need to do when the check box gets clicked
}
else
{
//Do another stuff...
}
}
You will need to do the same with KeyUp event in order to get the Space key press that could also activate the checkbox.

Categories