Check Control.Value for data - c#

I have several different controls (TextBoxes, DateTimePickers, MaskedTextBoxes) on a form that I would like to check to see if they contain any data. I have the following code in the Click event of my "Save" button:
private void radBtnSave_Click(object sender, EventArgs e)
{
this.Cancelled = false;
bool bValid = true;
foreach(Control control in this.Controls)
{
if (control.Tag == "Required")
{
if (control.Text == "" || control.Text == null)
{
errorProvider.SetError(control, "* Required Field");
bValid = false;
}
else
{
errorProvider.SetError(control, "");
}
}
}
if (bValid == true)
{
bool bSaved = A133.SaveData();
if (bSaved != true)
{
MessageBox.Show("Error saving record");
}
else
{
MessageBox.Show("Data saved successfully!");
}
}
}
This works fine for the TextBoxes and MaskedEditBoxes, however, it does not work for the DateTimePickers. For those, I know I need to check the .Value property, but I cannot seem to access that from the Control object (i.e. "control.Value == "" || control.Value == null").
Am I missing something obvious? Any suggestions of modifications I can make to this code to allow me to check the DateTimePicker values (or just to improve the code at all) will be greatly appreciated.

You need to cast them to a DateTimePicker:
DateTimePicker dtp = control as DateTimePicker;
if(dtp !=null)
{
//here you can access dtp.Value;
}
Also, use String.IsNullOrEmpty(control.Text) in the first part of your code.

There is no Value property for Controls; DateTimePicker, for example, creates its own property that is unique to it.
Unfortunately for you, there is no fully generic way of handling this from a single loop of Control objects. The best you can do is something along the lines of this:
if(control is DateTimePicker)
{
var picker = control as DateTimePicker;
// handle DateTimePicker specific validation.
}

You'll need to do something like this:
foreach(Control control in this.Controls)
{
if (control.Tag == "Required")
{
DateTimePicker dtp = control as DateTimePicker;
if (dtp != null)
{
// use dtp properties.
}
else if (control.Text == "" || control.Text == null)
{
errorProvider.SetError(control, "* Required Field");
bValid = false;
}
else
{
errorProvider.SetError(control, "");
}
}
}

Related

Clear cell contents in a data bound datagridview

I am trying to implement a delete functionality in my DataGridView to clear the contents of highlighted cells.
One of the columns contains a double, and when the value is less than zero I display it as blank. If the user edits the cell to blank, this is handled via the CellParsing event.
The DataGridView is databound using a BindingSource and BindingList.
The issue I'm having is that when I change the cell Value to blank via my clear function, the CellParsing event does not fire and I get a FormatException saying that "" is not a valid value for Double. When the user clears the cell, the CellParsing event fires and everything happens as expected.
The reason I am setting the value to blank is that some of the columns are text and others are numbers, and I'd like to be able to delete them all at once.
I've googled and searched through StackOverflow and haven't found something yet that will solve my issue. Is there a way to route this through the CellParsing event or some other obvious solution that I'm missing?
See the CellParsing and clearing code below.
System::Void dataGridViewWells_CellParsing(System::Object^ sender, System::Windows::Forms::DataGridViewCellParsingEventArgs^ e)
{
//Handle blank values in the mass column
e->ParsingApplied = false;
if(this->dataGridViewWells->Columns[e->ColumnIndex]->HeaderText == "Mass (ng)")
{
if(e->Value->ToString() == "" || e->Value->ToString() == " ")
{
e->Value = -1.0;
e->ParsingApplied = true;
}
}
}
void DeleteHighlightedCells(DataGridView^ dgv)
{
try
{
System::Windows::Forms::DataGridViewSelectedCellCollection^ sCells = dgv->SelectedCells;
for(int i = 0; i < sCells->Count; i++)
{
if(!sCells[i]->ReadOnly)
{
dgv->Rows[sCells[i]->RowIndex]->Cells[sCells[i]->ColumnIndex]->Value = "";
}
}
}
catch(Exception^ e)
{
LogError("Unable to delete contents of DataGridView cells: " + e->ToString());
}
}
System::Void dataGridViewWells_KeyDown(System::Object^ sender, System::Windows::Forms::KeyEventArgs^ e)
{
if(e->Control && e->KeyCode == Keys::C)
{
this->CopyContentsToClipBoard(this->dataGridViewWells);
}
if(e->Control && e->KeyCode == Keys::V)
{
this->PasteContentsFromClipBoard(this->dataGridViewWells);
}
if(e->KeyCode == Keys::Delete)
{
this->DeleteHighlightedCells(this->dataGridViewWells);
}
}
I ended up abandoning the CellParsing event and putting in a custom TypeConverter for my class property as was done in this question.
TypeConverter code:
public ref class MassTypeConverter : System::ComponentModel::TypeConverter
{
public:
virtual bool CanConvertFrom(System::ComponentModel::ITypeDescriptorContext^ context, Type^ sourceType) override
{
return sourceType == String::typeid || System::ComponentModel::TypeConverter::CanConvertFrom(context, sourceType);
}
virtual Object^ ConvertFrom(System::ComponentModel::ITypeDescriptorContext^ context, System::Globalization::CultureInfo^ culture, Object^ value) override
{
if(value != nullptr && value->GetType() == String::typeid)
{
//
double converted;
bool success = double::TryParse((String^)value, converted);
if(((String^)value) == "" || ((String^)value) == " ")
{
converted = -1.0;
success = true;
}
if(success)
{
return converted;
}
}
return System::ComponentModel::TypeConverter::ConvertFrom(context, culture, value);
}
};
And then put the following above my class Property:
[System::ComponentModel::TypeConverter(MassTypeConverter::typeid)]

C# DateTimePicker DataBinding Parse event not working

I have a datetimepicker that I am binding with nullable Date/Time column in dataset. I applied Format event successfully for null and not null object value. But, when I uncheck dtp control it does not get set to null in the dataset.
This is my code:
dtpBirthdate.DataBindings.Add(new Binding("Value", bsStaff, "birthDate", true));
dtpBirthdate.DataBindings["Value"].Format += new ConvertEventHandler(dtpFormat);
dtpBirthdate.DataBindings["Value"].Parse += new ConvertEventHandler(dtpParse);
Format and Parse events:
private void dtpFormat(object sender, ConvertEventArgs e)
{
Binding b = sender as Binding;
if(b != null)
{
DateTimePicker dtp = (b.Control as DateTimePicker);
if(dtp != null)
{
if (e.Value == null || e.Value == DBNull.Value)
{
dtp.Checked = false;
dtp.CustomFormat = " ";
e.Value = false;
}
else
{
dtp.Checked = true;
dtp.CustomFormat = "dd-MMM-yyyy";
dtp.Value = (DateTime) e.Value;
}
}
}
}
private void dtpParse(object sender, ConvertEventArgs e)
{
Binding b = sender as Binding;
if (b != null)
{
DateTimePicker dtp = (b.Control as DateTimePicker);
if (dtp != null)
{
if (dtp.Checked == false)
{
e.Value = DBNull.Value;
}
else
{
e.Value = dtp.Value;
}
}
}
}
After debugging, I found that it goes to infinite loop between parse and format events. What is wrong with my code?
Edit: There is also a datagridview binded to bsStaff bindingsource.
The following should fix the issue (see the comments in code):
private void dtpFormat(object sender, ConvertEventArgs e)
{
Binding b = sender as Binding;
if(b != null)
{
DateTimePicker dtp = (b.Control as DateTimePicker);
if (dtp != null)
{
if (e.Value == null || e.Value == DBNull.Value)
{
dtp.Checked = false;
dtp.CustomFormat = " ";
// e.Value = false;
// To prevent dtp.Value property setter setting Checked back to true
e.Value = dtp.Value;
}
else
{
dtp.Checked = true;
dtp.CustomFormat = "dd-MMM-yyyy";
//dtp.Value = (DateTime) e.Value;
// dtp.Value will be set to e.Value from databinding anyway
}
}
}
}
private void dtpParse(object sender, ConvertEventArgs e)
{
Binding b = sender as Binding;
if (b != null)
{
DateTimePicker dtp = (b.Control as DateTimePicker);
if (dtp != null)
{
if (dtp.Checked == false)
{
e.Value = DBNull.Value;
}
else
{
//e.Value = dtp.Value;
// Do nothing, e.Value is already populated with dtp.Value
}
}
}
}
But the whole idea is wrong from the beginning because it's based on data binding infrastructure hacks (the typical XY problem - to overcome the lack of DateTime? value property in DTP). Convert and Parse events are supposed to perform value conversion from data source value to control value and vice versa. They are not supposed to read or write control properties (it breaks the whole encapsulation), the information is provided through e.Value and e.DesiredType and the handlers are supposed to change the e.Value based on that information.
The right way is to create custom control inheriting DateTimePicker and implementing a (shadow) DateTime? Value property. The property getter and setter can apply the necessary logic (they are allowed to read/modify other properties). Then replace DTP controls with that custom control and simply bind to "Value" property w/o any binding event handlers.
Update: Here is a quick and dirty implementation of non binding approach mentioned:
public class CustomDateTimePicker : DateTimePicker
{
public CustomDateTimePicker()
{
Format = DateTimePickerFormat.Custom;
SetValueCore(null);
}
new public DateTime? Value
{
get { return Checked ? base.Value : (DateTime?)null; }
set
{
if (Value != value)
SetValueCore(value);
}
}
private void SetValueCore(DateTime? value)
{
if (value == null)
Checked = false;
else
base.Value = value.Value;
UpdateCustomFormat();
}
protected override void OnValueChanged(EventArgs eventargs)
{
UpdateCustomFormat();
base.OnValueChanged(eventargs);
}
private void UpdateCustomFormat()
{
CustomFormat = Value != null ? "dd-MMM-yyyy" : " ";
}
}
You are casting "Binding b = sender as Binding" before the null check. check if the sender is null before casting and you should be fine.
I noticed that you are using a Databinding event capture for both controls but on your first dtpFormat event handler you don't check for databinding values first.
Imho this line of code:
if (e.Value == null || e.Value == DBNull.Value)
needs to be changed to
if (e.Value == DBNull.Value || e.Value == null)
The issue is you need to set e.Value to something; but if you change it, it will fire parse again. Try setting it to it's original value.
e.Value = dtp.Value;
Here is a link to someone who has ran into this before. They were not using your DbNull.Value, but other than that it is nearly identical to what you are doing.
http://blogs.interknowlogy.com/2007/01/21/winforms-databinding-datetimepicker-to-a-nullable-type/
dtpParse is setting e.Value = dbNull.Value which will fire the dtpFormat as the value has changed which in turn sets e.Value = false which is different to dbNull.Value which will again fire dtpParse. Try removing the e.Value = false from dtpFormat

Trying to find controls

I want to add runat=server dynamically to a CheckBoxList so that it can be found by FindControl.
CheckBoxList cbl = new CheckBoxList();
cbl.ID = "cbl" + intQuestionCount.ToString();
// get choices from choice list
int intChoiceListId = Convert.ToInt32(detail.ChoiceListID);
var choiceList = (from cl in _svsCentralDataContext.SVSSurvey_ChoiceListItems
where cl.ChoiceListID == intChoiceListId
orderby cl.Description
select cl);
cbl.DataSource = choiceList;
cbl.DataTextField = "Description";
cbl.DataBind();
cbl.Visible = true;
cbl.CssClass = "PositionCol3";
questionsPanel.Controls.Add(cbl);
I have 2 recursive find control methods:
private HtmlControl FindHtmlControlByIdInControl(Control control, string id)
{
foreach (Control childControl in control.Controls)
{
if (childControl.ID != null && childControl.ID.Equals(id, StringComparison.OrdinalIgnoreCase)
&& childControl is HtmlControl
)
{
return (HtmlControl)childControl;
}
if (childControl.HasControls())
{
HtmlControl result = FindHtmlControlByIdInControl(childControl, id);
if (result != null)
{
return result;
}
}
}
return null;
}
private WebControl FindWebControlByIdInControl(Control control, string id)
{
foreach (Control childControl in control.Controls)
{
if (childControl.ID != null && childControl.ID.Equals(id, StringComparison.OrdinalIgnoreCase)
&& childControl is WebControl
)
{
return (WebControl)childControl;
}
if (childControl.HasControls())
{
WebControl result = FindWebControlByIdInControl(childControl, id);
if (result != null)
{
return result;
}
}
}
return null;
}
The screen is initially created dynamically (if !isPostback), based on an SQL record. The FindControl methods are used after this lot has been displayed, when the user clicks the 'Save' button.
Neither Find control method finds my CheckBoxList!!
You are adding controls through your code behind, they are already server side controls, you don't have to add runat="server". You are not finding them properly.
Make sure they are added to the page before you look for them.

get all control from multiple form in csharp

I want to get all the control from multiple form (Main, Two and Three) and
compare if the control tag equals the variable str_name and if true write the
value of str_value in c.Text.
the code:
private static Form[] getformular()
{
Main main = new Main();
Two f2 = new Two();
Three f3 = new Three();
Form[] form = { main, f2, f3};
return form;
}
private void initcontrol()
{
String str_name = "name";
String str_value = "value";
foreach(Form f in getformular())
{
foreach (Control c in f.Controls)
{
if (f != null && c = null)
{
if (c.Tag.Equals(str_name))
{
c.Text = str_value;
}
}
}
}
}
Could please someone help me?
First, as stated by #JonB some of conditional checking (ifs logic) in your current code seems off.
Second, looping through Form.Controls will only bring you all controls placed directly in the Form. For example if you have tab control (or any other container control) placed in form, and you have a textbox inside that tab control, you'll get only the tab control and couldn't find the textbox by looping through Form.Controls. You can solve that with recursive method as demonstrated below.
private void initcontrol()
{
String str_name = "name";
String str_value = "value";
var result = false;
foreach(Form f in getformular())
{
//if you want to check if f null, it should be here.
if(f != null) result = setControlText(f, str_name, str_value);
}
if(!result) MessageBox.Show("Control not found");
}
private bool setControlText(Control control, string str_name, string str_value)
{
var isSuccess = false;
foreach (Control c in control.Controls)
{
//if c is not null
if (c != null)
{
//check c's Tag, if not null and matched str_name set the text
if (c.Tag != null && c.Tag.Equals(str_name))
{
c.Text = str_value;
isSuccess = true;
}
//else, search in c.Controls
else isSuccess = setControlText(c, str_name, str_value);
//if control already found and set, exit the method now
if (isSuccess) return true;
}
}
return isSuccess;
}

Select and unselect checkboxes

i have a list of Checkbox's .
checkbox1,checkbox2....
i want to uncheck the checkbox if its is checked and vice versa.Is there any way to do this.
foreach (CheckBox cb in cbList) {
cb.Checked = !cb.Checked;
}
if (CheckBox1.Checked == true)
{
CheckBox1.Checked = false
}
else
{
CheckBox1.Checked = true
}
I don't know if you're working in ASP.NET, WPF, WinForms, ...
But it's as easy as check if checkbox is checked, then uncheck, and viceversa.
Or you can implement an extension method like:
public static class CheckboxExtensions
{
public static void ToggleChecked(this CheckBox some)
{
if(some != null)
{
if(some.Checked)
{
some.Checked = false;
}
else
{
some.Checked = true;
}
}
}
}
... And your actual code will look like this:
chkSome.ToggleChecked();
Try
checkBox1.Checked = !checkBox1.Checked;

Categories