How to set Validation for all controls in a user control? - c#

I am looking for the best way to set the validation group for all of the controls contained in a user control. Most of the controls in the control are created dynamically when the control is loaded. It has quite a few input fields and validators.
I would like to save time by setting the validation for all the controls and validators with some sort of function that could just loop through everything and set it.
It seems though that there is no consistent interface that includes validation group for all of the different controls that have the property.
Should I use reflection to check for Validation group, I know I can do this, but is there a better way?
We are using C# by the way.
Any help would be appreciated. Thanks!
EDIT: I put the answer down below for anyone who wants the code.

Just wanted to mark this answered.
Here is the code I used to set the validation group. I decided to go with using reflection, since I could check types for those I know have ValidationGroup, and cast and set, but there are a lot of types to check, and it could miss new controls that may be added in the future. Would have been sweet if the ValidationGroup were part of some kind of interface that things had to implement.
/// <summary>
/// this is an extension method to iterate though all controls in a control collection
/// put this in some static library somewhere
/// </summary>
/// <param name="controls"></param>
/// <returns></returns>
public static IEnumerable<Control> All(this ControlCollection controls)
{
foreach (Control control in controls)
{
foreach (Control grandChild in control.Controls.All())
yield return grandChild;
yield return control;
}
}
/// <summary>
/// this function uses reflection to check if the validation group exists, and then set it to the
/// specified string
/// </summary>
/// <param name="ValidationGroup"></param>
private void SetValidationGroup(string ValidationGroup)
{
//set the validation group for all controls
if (ValidationGroup.IsNotNullOrEmpty())
{
foreach (Control c in Controls.All())
{
var Properties = c.GetType().GetProperties();
var vg = Properties.Where(p => p.Name == "ValidationGroup").SingleOrDefault();
if (vg != null)
{
vg.SetValue(c, ValidationGroup, null);
}
}
}
}

I recently had a very similar problem- the soloution I used was to create a couple of extension methods that could loop over all child/descendent controls of a control, find ones of a particular type and then call a subroutine on them (this subroutine could for example, set any properties of a control). The code is below in VB.Net (sorry this is what we use at work, I'm sure a code translator should be able to sort this out for you).
Public Module ControlExtensionMethods
''' <summary>
''' Gets all validation controls used by a control.
''' </summary>
''' <param name="onlyGetVisible">If true, will only fetch validation controls that currently apply (i.e. that are visible). The default value is true.</param>
''' <returns></returns>
''' <remarks></remarks>
<Extension()>
Public Function GetAllValidationControls(ByVal target As Control, Optional ByVal onlyGetVisible As Boolean = True) As ReadOnlyCollection(Of BaseValidator)
Dim validators As New List(Of BaseValidator)
GetControlsOfType(Of BaseValidator)(target, Function(x) Not onlyGetVisible OrElse x.Visible = onlyGetVisible, validators)
Return validators.AsReadOnly()
End Function
''' <summary>
''' Gets if the control is in a valid state (if all child/descendent validation controls return valid)
''' </summary>
''' <returns></returns>
''' <remarks></remarks>
<Extension()>
Public Function IsValid(ByVal target As Control) As Boolean
Return target.GetAllValidationControls().All(Function(x)
x.Validate()
Return x.IsValid
End Function)
End Function
''' <summary>
''' Iteratively fetches all controls of a specified type/base type from a control and its descendents.
''' </summary>
''' <param name="fromControl"></param>
''' <param name="predicate">If provided, will only return controls that match the provided predicate</param>
''' <remarks></remarks>
<Extension()>
Public Function GetControlsOfType(Of T As Control)(ByVal fromControl As Control, Optional ByVal predicate As Predicate(Of T) = Nothing) As IList(Of T)
Dim results As New List(Of T)
GetControlsOfType(fromControl, predicate, results)
Return results
End Function
Private Sub GetControlsOfType(Of T As Control)(ByVal fromControl As Control, ByVal predicate As Predicate(Of T), ByVal results As IList(Of T))
'create default predicate that always returns true if none is provided
Dim cntrl As Control
If predicate Is Nothing Then predicate = Function(x) True
If fromControl.HasControls Then
For Each cntrl In fromControl.Controls
GetControlsOfType(Of T)(cntrl, predicate, results)
Next
End If
If TypeOf fromControl Is T AndAlso predicate(fromControl) Then
results.Add(fromControl)
End If
End Sub
End Module
An example of using this code to disable all validators:
Array.ForEach(myUserControl.GetAllValidationControls().ToArray(), sub(x) x.Enabled = False)

I was butting my head against this issue just now, and came up with an alternative solution that doesn't involve duck-typing:
string newGroup = "foo";
IEnumerable<BaseValidator> validators = this.Controls.OfType<BaseValidator>();
IEnumerable<Button> buttons = this.Controls.OfType<Button>();
foreach (var validator in validators)
validator.ValidationGroup = newGroup;
foreach (var button in buttons)
button.ValidationGroup = newGroup;
This also might be an alternative:
foreach (var c in this.Controls)
{
if (c is BaseValidator)
(c as BaseValidator).ValidationGroup = newGroup;
else if (c is Button)
(c as Button).ValidationGroup = newGroup;
}

Related

Use of Dynamic Keyword in .Net 3.5

I have written this code in visual studio 2013 utilizing .net v4.5. The problem I am having is that I am now having to drop down to .net v3.5 and the dynamic keyword is throwing an error as missing an assembly reference. Is there an equivalent type to 'dynamic' in .net v3.5 or a way for me to achieve the same results as below?
I thought I may have found my answer here, but var is throwing errors when I add the .Attributes or .Text property modifications.
private void CreateControl<T>(string objText,
Panel pnl,
string HTMLTag = "<td>",
string applicantID = "",
EventHandler hndl = null)
{
pnl.Controls.Add(new LiteralControl(HTMLTag));
dynamic obj = Activator.CreateInstance(typeof(T));
obj.Text = objText;
if (applicantID != string.Empty)
{
obj.Attributes.Add("ApplicantID", applicantID);
}
if (hndl != null)
{
obj.Click += new EventHandler(hndl);
}
pnl.Controls.Add(obj);
pnl.Controls.Add(new LiteralControl(HTMLTag.Insert(1, "/")));
}
Instead of trying to hack this together in some bound to fail way and since there isn't a 'dynamic' control in .net v3.5, I have instead decided to just completely forgo this method and wrote some overloads instead. This way seems safer at this point; works the same, just a bit more code...
#region CreateControl() Overloads
/// <summary>
/// Creates a LinkButton control.
/// </summary>
/// <param name="objText">.Text property of this LinkButton control.</param>
/// <param name="pnl">Panel this control will be attached to.</param>
/// <param name="hndl">Event handler attached to this LinkButton control.</param>
/// <param name="HTMLTag">Opening tag used to contain this control.</param>
private void CreateControl(string objText,
Panel pnl,
EventHandler hndl,
string HTMLTag)
{
pnl.Controls.Add(new LiteralControl(HTMLTag));
LinkButton obj = new LinkButton();
obj.Text = objText;
obj.Click += new EventHandler(hndl);
pnl.Controls.Add(obj);
pnl.Controls.Add(new LiteralControl(HTMLTag.Insert(1, "/")));
}
/// <summary>
/// Creates a Label control.
/// </summary>
/// <param name="objText">.Text property of this Label control.</param>
/// <param name="pnl">Panel this control will be attached to.</param>
/// <param name="HTMLTag">Opening tag used to contain this control.</param>
private void CreateControl(string objText,
Panel pnl,
string HTMLTag)
{
pnl.Controls.Add(new LiteralControl(HTMLTag));
Label obj = new Label();
obj.Text = objText;
pnl.Controls.Add(obj);
pnl.Controls.Add(new LiteralControl(HTMLTag.Insert(1, "/")));
}
/// <summary>
/// Creates the specified literal control.
/// </summary>
/// <param name="ControlText">HTML text containing instructions for creating the desired literal control.</param>
/// <param name="pnl">Panel this literal control will be attached to.</param>
private void CreateControl(string ControlText,
Panel pnl)
{
pnl.Controls.Add(new LiteralControl(ControlText));
}
#endregion
Is there an equivalent type to 'dynamic' in .net v3.5
No. dynamic requires .NET 4.0.
or a way for me to achieve the same results as below?
You could use reflection instead of dynamic to create the control and add your event handlers.
However, since this appears to be one of a few custom controls you're creating (given the attributes, etc), you may be able to constrain to an interface or base class, which would allow you to create the items and use those shared properties directly.
Based on your code, it looks like you're writing a generic method to pass in some unknown controls and attach them to a panel.
It also looks like you're dealing with different types of controls; i.e., not all WebControls have Text, and Attributes, AND Click properties;
This is a bit hacky but works in 3.5 - you can just use casting of the various underlying types or interfaces to access the needed properties, something like this:
private void CreateControl<T>(string objText, Panel pnl, string HTMLTag,
string applicantID, EventHandler hndl)
where T : Control, new()
{
pnl.Controls.Add(new LiteralControl(HTMLTag));
T obj = new T();
if (obj is ITextControl) (obj as ITextControl).Text = objText;
if (applicantID != string.Empty && obj is WebControl)
(obj as WebControl).Attributes.Add("ApplicantID", applicantID);
if (obj is IButtonControl)
{
(obj as IButtonControl).Text = objText;
if (hndl != null)
{
(obj as IButtonControl).Click += new EventHandler(hndl);
}
}
pnl.Controls.Add(obj as Control);
pnl.Controls.Add(new LiteralControl(HTMLTag.Insert(1, "/")));
}
Test code:
protected void Page_Load(object sender, EventArgs e)
{
var panel = new Panel();
CreateControl<Button>("test", panel, "<td>", "123", (s, args) => Console.WriteLine("hello!"));
CreateControl<Label>("test", panel, "<td>", "123", (s, args) => Console.WriteLine("hello!"));
CreateControl<Panel>("test", panel, "<td>", "123", (s, args) => Console.WriteLine("hello!"));
CreateControl<Literal>("test", panel, "<td>", "123", (s, args) => Console.WriteLine("hello!"));
//This won't compile because object doesn't fit <control> constraint
//CreateControl<object>("test", panel, "<td>", "123", (s, args) => Console.WriteLine("hello!"));
}
To be honest I'm not 100% sure I like this approach. I might use some more specific methods and possibly method overloading to get more specific with different types of control creation, but this may help point you in the right direction.
Note that optional parameters are also not yet "invented" in C# 3.0 which shipped with .net 3.5, so you have to actually pass in all of the values.
dynamic keyword is available on .net 4.x and is a simple way to store any kind of value, it just resolve his type in runtime. It has been useful to me working with JSON strings.
string jsonValue = "{name:'Pedro',lastName:'Mora'}";
dynamic Variable = new JavascriptSerializer().Deserialize<dynamic>(jsonValue);
return Variable.name;
//It will return "Pedro"
Thing is that you have to be sure that the value won't be null and the properties or attributes or methods or something refered to the object exists and it takes it's values on runtime.

How to disallow interaction on a view behind uipopovercontroller

I have a UIPopoverController that I am using and I have two buttons each displays a popup when clicked. However, I do not want the popup to be displayed at the same time - meaning I do not want the user to be able to press the one button and while the popup is displayed be able to press the other button. It seems like I have tried everything - disabling the user interaction on the buttons, hiding the view behind the pop up, using passthrough views for the pop and more. None of it works! The disabling of the user interaction seems to work for the most part but then stops disallowing the user to interact with the button and causes the application to crash...
popupView.PassthroughViews = new UIView[]{this.View.Superview, this.View, this.Gray}; //gray is another view that sits under the view that calls the popup
this.View.UserInteractionEnabled = false;
this.PositiveMeterBtn.UserInteractionEnabled = false;
this.View.Hidden = true;
My UIPopoverController is declared at the class level and I have even done code like this:
if(popupView != null)
return;
I still get multiple popups. I am using mono touch/xamarin - is this a bug with xamarin or an ios issue? Am I handling this in the correct manner?
I haven't worked with Xamarin before, but what's worked for me in native Objective-C is
[controller setModalInPopover:YES];
where controller is the view controller displayed within the popover.
From the UIViewController class reference:
#property(nonatomic, readwrite, getter=isModalInPopover) BOOL modalInPopover
The default value of this property is NO. Setting it to YES causes an owning popover controller to disallow interactions outside this view controller while it is displayed.
You can either make the popover modal but if it doesn't contain content that is meant to be modal, you shouldn't block the user.
Usually the better option is to make two helper methods and place them for instance in your app delegate. The methods take care that an existing popover is dismissed if another one is to be shown. This way you will have a maximum of on UIPopoverController and don't have to worry about dismissal.
/// <summary>
/// Shows a popover.
/// </summary>
/// <param name='controllerToShow'>the controller to show in the popover</param>
/// <param name='showFromRect'>the rectangle to present the popover from. Not used if showFromItem is specified.</param>
/// <param name='showInView'>the view the popover is hosted in</param>
/// <param name='showFromItem'>the bar button item the popover gets presented from.</param>
/// <param name='popoverContentSize'>the content size of the popover</param>
/// <param name='animated'>If set to <c>true</c>, animated the popover</param>
/// <param name='arrowDirection'>the allowed arrow directions</param>
/// <param name='onDismiss'>callback if the popover gets dismissed. Careful that the object that owns the callback doesn't outlive the popover controller to prevent uncollectable memory.</param>
public static void ShowPopover(UIViewController controllerToShow, RectangleF showFromRect, UIView showInView, UIBarButtonItem showFromItem, SizeF popoverContentSize, bool animated = true, UIPopoverArrowDirection arrowDirection = UIPopoverArrowDirection.Any, EventHandler onDismiss = null)
{
if(AppDelegateBase.popoverController != null)
{
AppDelegateBase.DismissPopover(false);
}
if(showFromItem == null && showFromRect.IsEmpty)
{
// Nothing to attach the popover to.
return;
}
popoverController = new UIPopoverController(controllerToShow);
if(!popoverContentSize.IsEmpty)
{
popoverController.SetPopoverContentSize(popoverContentSize, false);
}
if(onDismiss != null)
{
popoverController.DidDismiss += onDismiss;
}
// Send a notification that a popover will be presented.
NSNotificationCenter.DefaultCenter.PostNotificationName("WillPresentPopover", popoverController);
if(showFromItem != null)
{
popoverController.PresentFromBarButtonItem(showFromItem, arrowDirection, animated);
}
else
{
popoverController.PresentFromRect(showFromRect, showInView, arrowDirection, animated );
}
}
/// <summary>
/// Dismisses the popover presented using ShowPopover().
/// </summary>
/// <param name='animated'>If set to <c>true</c>, animates the dismissal</param>
public static void DismissPopover(bool animated = false)
{
if(popoverController != null)
{
popoverController.Dismiss(animated);
}
AppDelegateBase.popoverController = null;
}
private static UIPopoverController popoverController;
One thing you might try is using the method
-(BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender
And in that method check if one of your popover view controller's is on screen.
if (popupView.view.window) {
return NO;
} else {
return YES;
}

Change value of all controls of a specific type without causing indefinite loop

I have a situation where I have several (let's say 10 for now) DevExpress LookUpEdit controls (sort of like DropDown Controls for Windows) on several tabs on my form. All 10 of these controls are the same in that they use the same data source to get their information from. What I'm trying to do is if a value changes in ANY of the 10 controls, then I want it to change in the other 9 controls as well. Because I have other controls of this type on my form that I do not want to be changed, I simply added a string value to the Tag property and have a method search for all controls of this type with the Tag property set to a specific string.
I initially thought I might be able to create a generic method that would change the text for all other controls and assign it to the TextChanged event of each control but I soon found out that they cancel each other out once I assign the value of one control to another (because in essence, once I change the value of one control, it then calls the same method and tries to change the rest).
Sorry if it's confusing, but here's some code as to what I'm trying to do...for now, let's say I have just 2 controls...lookupWeight and lookupBicycleWeight. On the TextChanged event for each, I have this:
private void OnLookupWeight_TextChanged(object sender, EventArgs e)
{
OnLookupWeight_TextChanged<LookUpEdit>(sender, e);
}
which calls this:
private void OnLookupWeight_TextChanged<T>(object sender, EventArgs e)
{
var controls = GetAll(tabPageSpecifications, typeof(T));
foreach (var control in controls)
{
if (control.Tag != null)
if (control.Tag.ToString() == "Weight")
if(control.Name != (sender as LookUpEdit).Name)
(control as LookUpEdit).EditValue = (sender as LookUpEdit).Text;
}
}
GetAll is a simple method that returns all controls for a given Control, including sub-controls:
/// <summary>
/// method to get all child & sub-child controls within a control by type
/// </summary>
/// <param name="control">the control we're searching in (use this for the form)</param>
/// <param name="type">The control type we're looking for (i.e; TextBox)</param>
/// <returns></returns>
public IEnumerable<Control> GetAll(Control control, Type type = null)
{
var controls = control.Controls.Cast<Control>();
//check the all value, if true then get all the controls
//otherwise get the controls of the specified type
if (type == null)
return controls.SelectMany(ctrl => GetAll(ctrl, type)).Concat(controls);
else
return controls.SelectMany(ctrl => GetAll(ctrl, type)).Concat(controls).Where(c => c.GetType() == type);
}
I know my OnLookupWeight_TextChanged method isn't entirely generic because I cast to the type LookupEdit but I am just trying to get this to work at this point before going back and changing things.
As you can see, the line if(control.Name != (sender as LookUpEdit).Name) is where the OnLookupWeight_TextChanged gets fired again and basically cancels itself out.
Any help or diretion as to how to accomplish this would be great.
Just change the ones that don't already have the same Text value:
foreach (var control in controls)
{
if (control.Tag != null)
if (control.Tag.ToString() == "Weight")
if((control as LookUpEdit).EditValue != (sender as LookUpEdit).Text)
(control as LookUpEdit).EditValue = (sender as LookUpEdit).Text;
}
It sounds like the code in OnLookupWeight_TextChanged shouldn't be run when the text of the control is changed from within that routine. You can use an instance variable to disable running it except when the change comes from outside. For example:
private Boolean InProgress;
private void OnLookupWeight_TextChanged<T>(object sender, EventArgs e)
{
if (!InProgress)
{
InProgress=true;
var controls = GetAll(tabPageSpecifications, typeof(T));
foreach (var control in controls)
{
if (control.Tag != null)
if (control.Tag.ToString() == "Weight")
if(control.Name != (sender as LookUpEdit).Name)
(control as LookUpEdit).EditValue = (sender as LookUpEdit).Text;
}
InProgress = false;
}
}
Why don't you use the same bindingsource for all the 10 controls?
When you change the selected value in one of them all would change.

PropertyGrid control - modify the position of the central splitting vertical line

I have a PropertyGrid control in WinForms (http://msdn.microsoft.com/en-us/library/aa302326.aspx). Now I want to move the middle vertical line more to the left (It is always centered, but my keys are very short, while the values are Paths, which are long. The control places the line in the middle by default, eventhough the user can move it. In respect to user friendlyness, I would like to move the line more to the left programmatically. I have now searched both the WinForms designer properties as well as the members of the PropertyGrid control multiple times and have not found the option (nor any events concerning it).
Is it hidden from sight/modification by being private? Have I simply overseen it? (In that case, I am sincerely sorry) or how can I do this otherwise?
Yes, unfortunately this requires some reflection based hacks in order to be achieved.
Here is a sample extensions class:
PropertyGridExtensionHacks.cs
using System.Reflection;
using System.Windows.Forms;
namespace PropertyGridExtensionHacks
{
public static class PropertyGridExtensions
{
/// <summary>
/// Gets the (private) PropertyGridView instance.
/// </summary>
/// <param name="propertyGrid">The property grid.</param>
/// <returns>The PropertyGridView instance.</returns>
private static object GetPropertyGridView(PropertyGrid propertyGrid)
{
//private PropertyGridView GetPropertyGridView();
//PropertyGridView is an internal class...
MethodInfo methodInfo = typeof(PropertyGrid).GetMethod("GetPropertyGridView", BindingFlags.NonPublic | BindingFlags.Instance);
return methodInfo.Invoke(propertyGrid, new object[] {});
}
/// <summary>
/// Gets the width of the left column.
/// </summary>
/// <param name="propertyGrid">The property grid.</param>
/// <returns>
/// The width of the left column.
/// </returns>
public static int GetInternalLabelWidth(this PropertyGrid propertyGrid)
{
//System.Windows.Forms.PropertyGridInternal.PropertyGridView
object gridView = GetPropertyGridView(propertyGrid);
//protected int InternalLabelWidth
PropertyInfo propInfo = gridView.GetType().GetProperty("InternalLabelWidth", BindingFlags.NonPublic | BindingFlags.Instance);
return (int)propInfo.GetValue(gridView);
}
/// <summary>
/// Moves the splitter to the supplied horizontal position.
/// </summary>
/// <param name="propertyGrid">The property grid.</param>
/// <param name="xpos">The horizontal position.</param>
public static void MoveSplitterTo(this PropertyGrid propertyGrid, int xpos)
{
//System.Windows.Forms.PropertyGridInternal.PropertyGridView
object gridView = GetPropertyGridView(propertyGrid);
//private void MoveSplitterTo(int xpos);
MethodInfo methodInfo = gridView.GetType().GetMethod("MoveSplitterTo", BindingFlags.NonPublic | BindingFlags.Instance);
methodInfo.Invoke(gridView, new object[] { xpos });
}
}
}
To move the splitter position use the MoveSplitterTo extension method.
Use the GetInternalLabelWidth extension method to get the actual position of the splitter. Please note that I observed that until the SelectedObject is assigned and the PropertyGrid was not shown, GetInternalLabelWidth returns (-1).
Sample use:
using PropertyGridExtensionHacks;
//...
private void buttonMoveSplitter_Click(object sender, EventArgs e)
{
int splitterPosition = this.propertyGrid1.GetInternalLabelWidth();
this.propertyGrid1.MoveSplitterTo(splitterPosition + 10);
}
Here is a method that doesn't rely on directly using private methods or reflection. It does still use undocumented interfaces though.
In .NET 4.0 the PropertyGrid.Controls collection contains 4 controls. PropertyGrid.Controls.item(2) is an undocumented PropertyGridView (same type as in answer that uses reflection). The property PropertyGridView.LabelRatio adjusts the relative widths of the columns. The range of LabelRatio looks like it is 1.1 to 9. Smaller values make the left column wider.
I know that setting LabelRatio before you initially display the control works. However I'm not sure what all you need to do to make it take effect once the control is already displayed. You can google MoveSplitterTo to find .NET source code and look at the source for PropertyGridView to get more details. The calculations and operations involving it seem somewhat complicated and I didn't analyze them in detail.
LabelRatio is initially set to 2 (ie splits the available PropertyGrid width in half). Set it to 3 for thirds, 4 for quarter.
Code requires Imports System.Reflection
Public Sub MoveVerticalSplitter(grid As PropertyGrid, Fraction As Integer)
Try
Dim info = grid.[GetType]().GetProperty("Controls")
Dim collection = DirectCast(info.GetValue(grid, Nothing), Control.ControlCollection)
For Each control As Object In collection
Dim type = control.[GetType]()
If "PropertyGridView" = type.Name Then
control.LabelRatio = Fraction
grid.HelpVisible = True
Exit For
End If
Next
Catch ex As Exception
Trace.WriteLine(ex)
End Try
End Sub
To change size of Description Pane at bottom of PropertyGrid as lines of text
Public Sub ResizeDescriptionArea(grid As PropertyGrid, lines As Integer)
Try
Dim info = grid.[GetType]().GetProperty("Controls")
Dim collection = DirectCast(info.GetValue(grid, Nothing), Control.ControlCollection)
For Each control As Object In collection
Dim type = control.[GetType]()
If "DocComment" = type.Name Then
Const Flags As BindingFlags = BindingFlags.Instance Or BindingFlags.NonPublic
Dim field = type.BaseType.GetField("userSized", Flags)
field.SetValue(control, True)
info = type.GetProperty("Lines")
info.SetValue(control, lines, Nothing)
grid.HelpVisible = True
Exit For
End If
Next
Catch ex As Exception
Trace.WriteLine(ex)
End Try
End Sub

Databinding Enabled if false

I have a problem with databinding in a winforms-application.
In the following code i have a databinding to the enabled-property of a textbox. The enabled-state depends on the value of a checkbox.
tbAmount.DataBindings.Add("Enabled", checkBox, "Checked",
false, DataSourceUpdateMode.OnPropertyChanged);
in this code the textbox is enabled if the checkbox is checked. but i need it inverted. i want the textbox to be enabled if the checkbox is unchecked. How can i achieve this?
This should do it.
Binding bind = new Binding("Enabled", checkBox, "Checked");
bind.Format +=
(sender, e) =>
e.Value = !((bool)e.Value); // invert the checked value
textBox.DataBindings.Add(bind);
I know this is a very old post, but I have looked for something similar many times over the years and was never really happy with what I ended up using. Mike Park's answer is great, not only because it works, but because of how simple it is.
All I did was take Mike's answer and turn it into a Control extension. Thanks Mike!
Depending on where and how you use it, you may need to add a reference to System.Windows.Forms and a using System.Windows.Forms statement.
/// <summary>
/// Creates a DataBinding that allows you to bind to the Unchecked state instead of the normal Checked state.
///
/// Sample usage: In this case, I am enabling a Button when the CheckBox is unchecked.
/// // Defaults to Control Enabled property.
/// // Always bound to the DataSource Checked property.
/// YourButton.DataBindings.Add(YourButton.UncheckedBinding(YourCheckBox));
///
/// var binding = YourButton.UncheckedBinding(YourCheckBox);
/// YourButton.DataBindings.Add(binding);
///
/// Adapted - from answer by Mike Park answered Oct 18 '12 at 19:11
/// From: Databinding Enabled if false
/// Link: https://stackoverflow.com/questions/12961533/databinding-enabled-if-false
/// </summary>
/// <typeparam name="T">Constrained to be a type that inherits from ButtonBase. This includes CheckBoxes and RadionButtons.</typeparam>
/// <param name="control">The control that will consume the DataBinding.</param>
/// <param name="DataSource">The control to which we are binding. We will always bind to the Checked property.</param>
/// <returns>DataBinding that is bound to the Unchecked state instead of the usual Checked state.</returns>
public static Binding UncheckedBinding<T>(this Control control, T DataSource) where T : ButtonBase
{
return UncheckedBinding(control, "Enabled", DataSource);
}
/// <summary>
/// Creates a DataBinding that allows you to bind to the Unchecked state instead of the normal Checked state.
///
/// Sample usage: In this case, I am enabling a Button when the CheckBox is unchecked.
/// // Always bound to the DataSource Checked property.
/// YourButton.DataBindings.Add(YourButton.UncheckedBinding("Enabled", YourCheckBox));
///
/// var binding = YourButton.UncheckedBinding(YourCheckBox);
/// YourButton.DataBindings.Add(binding);
///
/// Adapted - from answer by Mike Park answered Oct 18 '12 at 19:11
/// From: Databinding Enabled if false
/// Link: https://stackoverflow.com/questions/12961533/databinding-enabled-if-false
/// </summary>
/// <typeparam name="T">Constrained to be a type that inherits from ButtonBase. This includes CheckBoxes and RadionButtons.</typeparam>
/// <param name="control">The control that will consume the DataBinding.</param>
/// <param name="DataSource">The control to which we are binding. We will always bind to the Checked property.</param>
/// <param name="PropertyName">The name of the property that is being bound.</param>
/// <returns>DataBinding that is bound to the Unchecked state instead of the usual Checked state.</returns>
public static Binding UncheckedBinding<T>(this Control control, string PropertyName, T DataSource) where T : ButtonBase
{
var binding = new Binding(PropertyName, DataSource, "Checked");
binding.Format += (sender, e) => e.Value = !((bool)e.Value);
return binding;
}

Categories

Resources