data binding non-strings to TextBox.Text (WinForms)
I'm storing a whole bunch of settings for my winforms program in various .settings files.
Included in these settings are System.Drawing.Point
, System.Drawing.Location
, System.TimeSpan
, System.DateTime
, etc...
When I bind a form's Location
to a System.Drawing.Location
, and call the .Save()
method, it all seems to work fine. That is, since there doesn't seem to be a need for a cast, the form's System.Drawing.Location
is directly compatible with the System.Drawing.Location
setting stored in the .settings file.
Additionally, if I say TimeSpan tim开发者_如何学JAVAeSpan = Settings.Duration;
that also works fine.
Now, I have made a large settings form, where the user can adjust various parameters, including the various DateTime
and TimeSpan
settings. These are visible and editable in many TextBox
, which I have data bound in the following way:
Settings DefaultSettings = Settings.Default;
TextBox1.DataBindings.Add(("Text", DefaultSettings, "Duration", false, DataSourceUpdateMode.OnValidation, new TimeSpan(00, 30, 00));
The TimeSpan
is visible in the TextBox
, however when I try to edit it and call Save()
on the settings data source, I get the following error:
Value of '0' is not valid for 'Value'. 'Value' should be between 'Minimum' and 'Maximum'. Parameter name: Value
The error originates from the Visual Studio generated code block:
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("00:30:00")]
public global::System.TimeSpan StartWorkDay {
get {
return ((global::System.TimeSpan)(this["Duration"]));
}
set {
this["Duration"] = value;
}
}
I think the problem is caused by the fact that it's trying to turn a string into a System.TimeSpan
, and the various other classes I have in my .settings file.
Since I'm binding them using the DataBindings.Add(
which accepts strings for the parameters, I can't cast or use the new keyword there.
I could handle it all manually in code: updating the settings file by constructing the objects parameter-by-parameter, but I have so many settings stored in so many TextBoxes and NumericUpDowns that I would prefer to just bind them straight to the TextBox
, assuming that's possible.
What is the easiest way I can achieve this?
You could declare a “conversion property” (I just invented that term) in the Settings
class:
public class Settings
{
// The real property
public TimeSpan StartWorkDay { get; set; }
// The conversion property
public string StartWorkDayString
{
get
{
return StartWorkDay.ToString();
// (or use .ToString("...") to format it)
}
set
{
StartWorkDay = TimeSpan.Parse(value);
// (or use TryParse() to avoid throwing exceptions)
}
}
}
... and then bind the textbox to that.
I tried the following code in a sample windows form application and it did the save without any exceptions.
// Define the settings binding source
private System.Windows.Forms.BindingSource settingsBindingSource;
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.durationTextBox = new System.Windows.Forms.TextBox();
this.settingsBindingSource = new BindingSource(this.components);
this.settingsBindingSource.DataSource = typeof(WindowsFormsApplication1.Properties.Settings);
this.durationTextBox.DataBindings.Add(new Binding("Text", this.settingsBindingSource, "Duration", true));
}
// In the form load event where the textbox is displayed
private void Form1_Load(object sender, System.EventArgs e)
{
settingsBindingSource.DataSource = Settings.Default;
}
// save button click
private void button1_Click_1(object sender, System.EventArgs e)
{
// This saved the settings, without any exceptions
Settings.Default.Save();
}
Hope it helps.
I came up with a somewhat-elegant solution which you might be interested in:
Since the problem seemed to be that I was unable to cast or construct the data types I had in the .settings file from simple text boxes as I was using data binding, I instead made some custom controls.
For example, the TimeSpans now use a TimeSpanPicker
which I made out of a DateTimePicker
control, with the date disabled, the up/down toggles on, and the Value
property is converted to a TimeSpan from within the picker control.
The added advantage of this method is that I don't need to do a lot of the validation I needed to before with text boxes, as the TimeSpanPicker base control DateTimePicker will only show valid times. What little validation I do need to do can be done in the Set{} property, so I don't need to define event handlers.
This seems to be working well! Now all I need to do is replace all the text boxes with custom controls.
精彩评论