I want to check whether the value entered in a DevExpress Control is empty, but my Validation always returns false. For this reason, I am unable to perform further operations.
If you can help I'd appreciate it.
public static class ValidateHelpers {
public static bool validate(Form f, params Control[] control) {
bool result = true;
if (control != null) {
KgsDxValidationProvider prov = new KgsDxValidationProvider { ValidationMode = ValidationMode.Auto };
ConditionValidationRule notEmptyValidationRule = new ConditionValidationRule {
ConditionOperator = ConditionOperator.IsNotBlank,
ErrorText = "You Must Enter A Value",
ErrorType = ErrorType.Critical
};
foreach (var item in control) {
prov.SetValidationRule(item, notEmptyValidationRule);
result = false;
}
f.ValidateChildren();
}
return result;
}
}
You don't need to validate all childrens on your form. This will do what you want:
private bool Validate(params Control[] controls)
{
bool result = controls == null || !controls.Any();
if (controls != null)
{
DXValidationProvider provider = new DXValidationProvider { ValidationMode = ValidationMode.Auto };
ConditionValidationRule noEmptyValues = new ConditionValidationRule
{
ConditionOperator = ConditionOperator.IsNotBlank,
ErrorText = #"You must enter a value",
ErrorType = ErrorType.Critical
};
foreach (Control control in controls)
{
provider.SetValidationRule(control, noEmptyValues);
}
result = provider.Validate(); //Validate all controls associated with the provider
}
return result;
}
If you need further assistance for custom validation etc. you can check this link.
Related
I want to create global class(So I have to write it only once, not in all forms )that should detect if the global int is certain number and then overwrite text in label that says what is wrong.
For example when your name is too short it will says that your name is too short.
I know that you can do this in form, but I want whole new separated class because I plan to do this for 3 forms, so I would have to copy and paste the same errors etc... in each of them.
example:
Code in form register_menu.cs
public void getErrorNumber()
{
if (char_amount_username < 3 || textBox_username.Text == "Username")
{
Variables.error_number = 1;
}
else if (email_adress.Contains("#") != true || textBox_emailadress.Text == "Email adress")
{
Variables.error_number = 2;
}
else if (char_amount_password < 7 || textBox_password.Text == "Password")
{
Variables.error_number = 3;
}
else if (textBox_password.Text != textBox_passwordconfirm.Text)
{
Variables.error_number = 4;
}
else
{
Variables.error_number = 0;
}
}
private void button1_Click_1(object sender, EventArgs e)
{
ErrorCheck();
}
Code in class named GlobalErrorChecker.cs
namespace Xenious
{
internal class ErrorVariable
{
public static int error_number;
public void ErrorCheck()
getErrorNumber();
{
if (ErrorVariable.error_number is 1) ;
{
register_menu.error_msg.Text = "Your username is invalid!\n ⬤ Username must be avaiable\n ⬤ Minimum lenght of username is 4 ";
register_menu.displayERROR(true);
}
if(ErrorVariable.error_number is 2);
{
register_menu.error_message.Visible = true;
register_menu.error_msg.Text = "Your password is invalid!\n ⬤ Minimum lenght of password is 8 ";
register_menu.ICON_password_error.Visible = true;
}
if (ErrorVariable.error_number is 6) ;
{
login_menu.error_message.Visible = true;
login_menu.error_msg.Text = "Your username and password do not match!";
login_menu.ICON_username_error.Visible = true;
login_menu.ICON_password_error.Visible = true;
}
}
}
}
This is just example code how I want to do this, I have multiple problems.
First problem is that class GlobalErrorChecker.cs doesnt detect any controls from forms at all. I tried to fix this by looking online but I could find anything.
Second problem is that it says register_menu.ICON_password_error is unavaiable due to protection error CS0122....
I tried quite a huge amount of different methods how to do this, but I only found how to do this between 2 diffent forms, not between form and new class
Consider using a validation library like FluentValidation.
First create a class with properties to validate e.g.
public class Person
{
public string UserName { get; set; }
public string EmailAddress { get; set; }
public string Password { get; set; }
public string PasswordConfirmation { get; set; }
}
Create a validator.
public class PersonValidator : AbstractValidator<Person>
{
public PersonValidator()
{
RuleFor(person => person.UserName)
.NotEmpty()
.MinimumLength(3);
RuleFor(person => person.EmailAddress).EmailAddress();
RuleFor(person => person.Password.Length).GreaterThan( 7);
RuleFor(person => person.Password).Equal(p => p.PasswordConfirmation);
}
}
Create a new instance of the class, in this case Person. Populate values from your controls and than perform validation via Validate off the PersonValidator.
Below is a mock-up which uses StringBuilder to create a string which can be presented to the user.
Person person = new Person()
{
UserName = "billyBob",
Password = "my#Password1",
EmailAddress = "billyBob#gmailcom",
PasswordConfirmation = "my#Password1"
};
PersonValidator validator = new PersonValidator();
ValidationResult result = validator.Validate(person);
if (result.IsValid)
{
// person is valid
}
else
{
StringBuilder builder = new StringBuilder();
foreach (var error in result.Errors)
{
builder.AppendLine(error.ErrorMessage);
}
}
Dig in to ValidationResult if you need to inspect individual errors like PropertyName (Name of the property being validated) and ComparisonValue (Value that the property should not equal).
Note The email address validator only checks if an email address has a # so if you need more custom work is needed.
Making a static Extension Method
is one way to "create global class (so I have to write it only once...)". This answer will explore this option step-by-step.
First ask "what info is needed to determine a valid form?" Define these requirements in an interface:
interface IValidate
{
// Inputs needed
public string Username { get; }
public string Email { get; }
public string Password { get; }
public string Confirm { get; }
}
Now declare an Extension Method for "any" form that implements IValidate (this is the global class you asked about).
static class Extensions
{
public static int ValidateForm(this IValidate #this, CancelEventArgs e)
{
if (#this.Username.Length < 3) return 1;
if (!#this.Email.Contains("#")) return 2;
if (#this.Password.Length < 7) return 3;
if (!#this.Password.Equals(#this.Confirm)) return 4;
return 0;
}
}
The Form classes will be able to call the extension using this.
var e = new new CancelEventArgs();
int error_number = this.ValidateForm(e);
Example of Form Validation
For each of your 3 forms, implement the interface. This just means that the 3 form classes are making a promise or contract to provide the information that the interface requires (in this case by retrieving the text from the textboxes).
public partial class MainForm : Form, IValidate
{
#region I M P L E M E N T I N T E R F A C E
public string Username => textBoxUsername.Text;
public string Email => textBoxEmail.Text;
public string Password => textBoxPassword.Text;
public string Confirm => textBoxConfirm.Text;
#endregion I M P L E M E N T I N T E R F A C E
.
.
.
}
Then call the extension method when any textbox loses focus or receives an Enter key.
public partial class MainForm : Form, IValidate
{
public MainForm()
{
InitializeComponent();
foreach (Control control in Controls)
{
if(control is TextBox textBox)
{
textBox.TabStop = false;
textBox.KeyDown += onAnyTextboxKeyDown;
textBox.Validating += onAnyTextBoxValidating;
textBox.TextChanged += (sender, e) =>
{
if (sender is TextBox textbox) textbox.Modified = true;
};
}
}
}
private void onAnyTextBoxValidating(object? sender, CancelEventArgs e)
{
if (sender is TextBox textBox)
{
// Call the extension method to validate.
ErrorInt #int = (ErrorInt)this.ValidateForm(e);
if (#int.Equals(ErrorInt.None))
{
labelError.Visible = false;
buttonLogin.Enabled = true;
return;
}
else if (textBox.Modified)
{
buttonLogin.Enabled = false;
BeginInvoke(() =>
{
switch (#int)
{
case ErrorInt.Username: textBoxUsername.Focus(); break;
case ErrorInt.Email: textBoxEmail.Focus(); break;
case ErrorInt.Password: textBoxPassword.Focus(); break;
case ErrorInt.Confirm: textBoxConfirm.Focus(); break;
}
labelError.Visible = true;
labelError.Text = typeof(ErrorInt)
.GetMember(#int.ToString())
.First()?
.GetCustomAttribute<DescriptionAttribute>()
.Description;
textBox.Modified = false;
textBox.SelectAll();
});
}
}
}
private void onAnyTextboxKeyDown(object? sender, KeyEventArgs e)
{
if (sender is TextBox textbox)
{
if (e.KeyData.Equals(Keys.Return))
{
// Handle the Enter key.
e.SuppressKeyPress = e.Handled = true;
MethodInfo? validate = typeof(TextBox).GetMethod("OnValidating", BindingFlags.Instance | BindingFlags.NonPublic);
CancelEventArgs eCancel = new CancelEventArgs();
validate?.Invoke(textbox, new[] { eCancel });
}
}
}
.
.
.
}
Where:
enum ErrorInt
{
None = 0,
[Description("Username must be at least 3 characters.")]
Username = 1,
[Description("Valid email is required.")]
Email = 2,
[Description("Password must be at least 7 characters.")]
Password = 3,
[Description("Passwords must match.")]
Confirm = 4,
}
I have a combobox in my application, where items are loaded asynchronously depending on a search text you can enter in the text field.
This works fine, but every time the text of the first item is automatically selected during updating the datasource of the combobox.
This leads to unintended behaviour, because I need to have the search text entered by the user to stay in the textfield of the combobox until a selection is done by the user and not automatically overwrite the text with the first entry.
This is my code:
public partial class ProductGroupDescription : UserControl, Interfaces.TabPages.ITabPageProductGroupDescription
{
private Services.IProductGroupDescriptionService _ApplicationService;
public BindingList<ProductGroup> ProductGroups { get; set; } = new BindingList<ProductGroup>();
public string ProductGroupSearchText { get; set; } = string.Empty;
public ProductGroupDescription(Services.IProductGroupDescriptionService applicationService)
{
InitializeComponent();
InitialSetupControls();
_ApplicationService = applicationService;
}
public void InitialSetupControls()
{
var pgBindingSource = new BindingSource();
pgBindingSource.DataSource = ProductGroups;
Cbo_ProductGroup.DataSource = pgBindingSource.DataSource;
Cbo_ProductGroup.DataBindings.Add("Text", ProductGroupSearchText, "");
}
private async void Cbo_ProductGroup_TextChanged(object sender, EventArgs e)
{
if (Cbo_ProductGroup.Text.Length >= 2)
{
ProductGroupSearchText = Cbo_ProductGroup.Text;
Cbo_ProductGroup.SelectedIndex = -1;
bool withStopFlagged = Chk_StopFlag_PGs_Included.Checked;
List<ProductGroup> list = await _ApplicationService.GetProductGroupBySearchString(ProductGroupSearchText, withStopFlagged);
if (list != null && list.Count > 0)
{
ProductGroups.Clear();
list.ForEach(item => ProductGroups.Add(item));
Cbo_ProductGroup.DroppedDown = Cbo_ProductGroup.Items.Count > 0 && Cbo_ProductGroup.Focused;
}
}
}
}
I tried to set Cbo_ProductGroup.SelectedIndex = -1, but it does not solve my issue here.
I also saw this on SO: Prevent AutoSelect behavior of a System.Window.Forms.ComboBox (C#)
But is there really no simpler solution to this issue?
I got it to work now.
It worked, when I removed the binding of the text field of the combobox
Cbo_ProductGroup.DataBindings.Add("Text", ProductGroupSearchText, "");
and set the new (old) value directly to the text field of the combobox.
Cbo_ProductGroup.Text = searchText;
In this case, a new event Text_Changed is fired and so the application has a infinite loop. So I used a property (ShouldTextChangedEventBeIgnored), if the Text_Changed event should be ignored.
Thanks to #CaiusJard for many hints in the comments.
This is my final code:
public partial class ProductGroupDescription : UserControl, Interfaces.TabPages.ITabPageProductGroupDescription
{
private ApplicationLogic.Interfaces.Services.IProductGroupDescriptionService _ApplicationService;
public BindingList<ProductGroup> ProductGroups { get; set; } = new BindingList<ProductGroup>();
public bool ShouldTextChangedEventBeIgnored { get; set; } = false;
public ProductGroupDescription(ApplicationLogic.Interfaces.Services.IProductGroupDescriptionService applicationService)
{
_ApplicationService = applicationService;
InitializeComponent();
InitialSetupControls();
}
public void InitialSetupControls()
{
var pgBindingSource = new BindingSource();
pgBindingSource.DataSource = ProductGroups;
Cbo_ProductGroup.DataSource = pgBindingSource.DataSource;
}
private async Task<List<ProductGroup>> LoadProductGroupItems(string searchText)
{
bool withStopFlagged = Chk_StopFlag_PGs_Included.Checked;
return await _ApplicationService.GetProductGroupBySearchString(searchText, withStopFlagged);
}
private async Task SetProductGroupSearchBoxItems(List<ProductGroup> list, string searchText)
{
await Task.Run(() =>
{
if (list != null && list.Count > 0)
{
ShouldTextChangedEventBeIgnored = true;
Cbo_ProductGroup.Invoke((c) =>
{
ProductGroups.Clear();
list.ForEach(item => ProductGroups.Add(item));
c.DroppedDown = c.Items.Count > 0 && c.Focused;
c.Text = searchText;
c.Select(c.Text.Length, 0);
});
ShouldTextChangedEventBeIgnored = false;
}
});
}
private async void Cbo_ProductGroup_TextChanged(object sender, EventArgs e)
{
try
{
if (Cbo_ProductGroup.Text.Length >= 2 && ShouldTextChangedEventBeIgnored == false)
{
string searchText = Cbo_ProductGroup.Text;
List<ProductGroup> list = await LoadProductGroupItems(Cbo_ProductGroup.Text);
await SetProductGroupSearchBoxItems(list, searchText);
}
}
catch(Exception ex)
{
System.Diagnostics.Trace.Write(ex);
}
}
}
I have these properties on a form.
public enum LanguageID
{
en, fr, de, it, ro
}
[Browsable(false)]
public Language[] Languages = new Language[]()
{
new Language { LangID = LanguageID.en, TranslatedText = "One" },
new Language { LangID = LanguageID.fr, TranslatedText = "Un"},
new Language { LangID = LanguageID.de, TranslatedText = "Einer"}
// and so on, for all other languages
}
public class Language
{
public LanguageID LangID { get; set; } = LanguageID.en;
public string TranslatedText { get; set; } = "One";
}
In design-time, user can change LanguageID property.
I added some custom Control objects on my form. In those objects constructors I want to access form's public property Languages, to be able to set a property of my custom controls according to selected LanguageID from form's property.
I've tried the solution from this post, but Site property will be set only in design-time, not in runtime. In runtime Site property is null.
public ContainerControl ContainerControl
{
get { return _containerControl; }
set { _containerControl = value; }
}
private ContainerControl _containerControl = null;
// Custom object constructor
public MyControl()
{
var langID = ((Form)ContainerControl).LanguageID; // the problem is here, ContainerControl is populated in DesignMode, but not in runtime. In runtime it's value is null
var selectedLang = Array.Find(Form.Languages, l => l.LangID = langID);
// code to set text here
}
public override ISite Site
{
get { return base.Site; }
set
{
base.Site = value;
if (value == null)
{
return;
}
IDesignerHost host = value.GetService(
typeof(IDesignerHost)) as IDesignerHost;
if (host != null)
{
IComponent componentHost = host.RootComponent;
if (componentHost is ContainerControl)
{
ContainerControl = componentHost as ContainerControl;
}
}
}
}
If this is not the good approach, please, I need some advice.
Each controller has a parent object and you can use the following code to get the form:
Type type = this.Parent.GetType();
Control x = this.Parent;
while (type.BaseType.Name != "Form")
{
x = x.Parent;
type = x.GetType();
}
// HERE x is your form
Or as a method:
public Form GetParentForm()
{
Type type = this.Parent.GetType();
Control x = this.Parent;
while (type.BaseType.Name != "Form")
{
x = x.Parent;
type = x.GetType();
}
return (Form)x;
}
The loop is needed because your control might be inside another container inside of the form.
I need to cast different objects to different types using the literal string name. Some example code:
string controlName = "Control";
string stringName = "string";
string panelName = "Panel";
var x = Panel();
((Control)x).Name = "SomeName";
The above code works of course, but instead of this line
((Control)x).Name = "Normal";
How do I use the line
((controlName)x).Name = "Awesome";
I hope this makes sense, but if I need to explain further I can try.
I am creating a series of questions defined in an xml schema. The Question will vary such as
1. What time did this happen.
2 Why did this happen.
3. What type was this(type 1,type 2, type3)
All of these are read by one base control. 1 needs the answer control to be a date time picker, two needs a textbox, 3 needs a combobox.
I would subscribe to the textchange event of the textbox, the value changed event of the datetimepicker, and the selectedindexchange event of the combobox.
This is oversimplifying it, what I am actually doing is with controls and created events.
The way I am handling it now, is a gigantic case statement. I wondered if there was an easier way to do with with conversion of the control to the type defined in the xml document(string value)
EDIT*
Code as was asked for
namespace ScriptControl
{
public partial class ScriptItem
{
public FollowupEvent ActiveEvent{get;set;}
public event EventHandler AnswerChanged;
#region Constructors
public ScriptItem()
{
}
public ScriptItem(DataRow row)
{
}
public ScriptItem(XElement xelem,FollowupEvent activeEvent,int instanceID)
{
ActiveEvent = activeEvent;
InstanceID = instanceID;
try
{
Question = xelem.Elements("Text").First().Value.ToString();
AnswerType = xelem.Elements("Type").First().Value.ToString();
ControlType = xelem.Elements("Control").First().Attribute("Type").Value.ToString();
ActivityID = Convert.ToInt32(xelem.Attribute("ID").Value.ToString());
ScriptItemType = xelem.Elements("ScriptItemType").First().Value.ToString();
ScriptItemQuestionType = xelem.Elements("QuestionType").First().Value.ToString();
InputControl = ConfigureInputControl(xelem.Elements("Control").First().Attribute("Type").Value.ToString());
QuestionControl = ConfigureQuestionControl(xelem.Elements("Control").First().Attribute("Type").Value.ToString());
Prompt = xelem.Elements("Prompt").First().Value.ToString();
}
catch { }
}
#endregion
#region Public Properties
public string Prompt { get; set; }
public Panel QuestionPanel = new Panel();
public int ActivityID { get; set; }
public string Question { get; set; }
public string AnswerType { get; set; }
public object Result { get; set; }
public Control InputControl { get; set; }
public string ControlType { get; set; }
public Control QuestionControl { get; set; }
public string ScriptItemType { get; set; }
public string ScriptItemQuestionType { get; set; }
public int InstanceID { get; set; }
public ScriptControl.Entities.ScriptControlBase ScriptBaseControl { get; set; }
#endregion
public Control ConfigureInputControl(string controlType)
{
switch (controlType)
{
case "Checkbox":
InputControl = new CheckBox();
break;
case "BooleanQuestion":
InputControl = new BooleanQuestion();
((BooleanQuestion)InputControl).AnswerChanged += ScriptItem_AnswerChanged;
((BooleanQuestion)InputControl).SetQuestion(Question);
break;
case "TextBox":
InputControl = new TextBox();
((TextBox)InputControl).KeyDown += ScriptItem_AnswerChanged;
break;
case "RadioButton":
InputControl = new RadioButton();
break;
case "DropDown":
InputControl = new RadioButton();
break;
case "DateTimePicker":
InputControl = new DateTimePicker();
((DateTimePicker)InputControl).KeyDown += ScriptItem_AnswerChanged;
break;
case ".CustomControls.SmartParts.CauseForRepair":
case".CustomControls.SmartParts.Airlines":
case ".CustomControls.SmartParts.DREntry":
InputControl = GetUIControl();
((FN_ControlBase)InputControl).PropertyChanged += ScriptItem_AnswerChanged;
break;
}
return InputControl;
}
private void ScriptItem_AnswerChanged(object sender, EventArgs e)
{
Dictionary<string, object> workFlowParams = new Dictionary<string, object>();
switch (ControlType)
{
case "BooleanQuestion":
Control x = ((Control)sender).Parent.Parent.Parent;
Result = ((BooleanQuestion)x).Answer;
workFlowParams.Add("QuestionID",Activity);
workFlowParams.Add("InstanceID", InstanceID);
workFlowParams.Add("Result",Result);
break;
case "TextBox":
if (((KeyEventArgs)e).KeyValue == 13)
{
Result = ((TextBox)sender).Text;
workFlowParams.Add("QuestionID", Activity);
workFlowParams.Add("InstanceID", InstanceID);
workFlowParams.Add("Result", Result);
}
break;
case "DateTimePicker":
if (((KeyEventArgs)e).KeyValue == 13)
{
Result = ((DateTimePicker)sender).Text;
workFlowParams.Add("QuestionID", Activity);
workFlowParams.Add("InstanceID", InstanceID);
workFlowParams.Add("Result", Result);
}
break;
case ".CustomControls.SmartParts.Airlines":
case ".CustomControls.SmartParts.CauseForRepairUI":
case ".CustomControls.SmartParts.CancelCallUI":
case ".CustomControls.SmartParts.CostCenter":
case ".CustomControls.SmartParts.ReadyToBill":
case ".CustomControls.SmartParts.TemporaryFix":
case ".CustomControls.SmartParts.BrakeRepairFollowup":
case ".CustomControls.SmartParts.DREntry":
default:
if (((PropertyChangedEventArgs)e).PropertyName == "WorkComplete" & Convert.ToBoolean(((.CustomControls.FN_ControlBase)sender).GetPropertyValue("WorkComplete")) == true)
{
foreach (var propty in ((.CustomControls.FN_ControlBase)sender).GetType().GetProperties())
{
if (ActiveEvent.HasProperty(propty.Name) & propty.Name != "EventID")
{
ActiveEvent.SetPropertyValue(propty.Name, ((Control)sender).GetPropertyValue(propty.Name));
}
}
}
workFlowParams.Add("QuestionID", Activity);
workFlowParams.Add("InstanceID", InstanceID);
workFlowParams.Add("Result", ActiveEvent);
break;
}
AnswerChanged(workFlowParams, e);
}
public Control ConfigureQuestionControl(string controlType)
{
switch (controlType)
{
case "BooleanQuestion":
((BooleanQuestion)InputControl).SetQuestion(Question);
break;
case "TextBox":
QuestionControl = new Label { Visible = true, Location = new Point(0, 0), Text = Question};
break;
case "DateTimePicker":
QuestionControl = new Label { Visible = true, Location = new Point(0, 0), Text = Question};
break;
}
return QuestionControl;
}
public Control ConfigureControl()
{
var height = 0;
var width = 0;
ScriptBaseControl = new ScriptControl.Entities.ScriptControlBase();
if (InputControl is BooleanQuestion || ScriptItemType == "Control")
{
InputControl = ConfigureInputControl(ControlType);
ScriptBaseControl.AddControl(InputControl);
ScriptBaseControl.SetPrompt(Prompt);
foreach (Control c in ScriptBaseControl.FilterControls(ctl => !(ctl is Panel) && !(ctl is FlowLayoutPanel) && !(ctl is GroupBox) && !(ctl is ScriptControlBase)))
{
height = height + c.Height;
if (c.Width > width)
{
width = c.Width;
}
}
ScriptBaseControl.Size = new Size(width, height);
}
else
{
FlowLayoutPanel x = new FlowLayoutPanel();
x.Controls.Add(QuestionControl);
x.Controls.Add(InputControl);
foreach (Control c in ScriptBaseControl.FilterControls(ctl => !(ctl is Panel) && !(ctl is FlowLayoutPanel) && !(ctl is GroupBox) && !(ctl is ScriptControlBase)))
{
height = height + c.Height;
if (c.Width > width)
{
width = c.Width;
}
}
x.Size = new Size(width, height);
ScriptBaseControl.Size = x.Size;
ScriptBaseControl.AddControl(x);
ScriptBaseControl.SetPrompt(Prompt);
}
return ScriptBaseControl;
}
private Control GetUIControl()
{
Control uiControl = new Control();
switch (ControlType)
{
case ".CustomControls.SmartParts.Air":
uiControl = new .CustomControls.SmartParts.Airlines(ActiveEvent.EventID) { ExternalSave = true};
break;
case ".CustomControls.SmartParts.CauseFor":
uiControl = new .CustomControls.SmartParts.CauseForRepairUI() { ExternalSave = true };
break;
case ".CustomControls.SmartParts.Cancel":
uiControl = new .CustomControls.SmartParts.CancelCallUI() { ExternalSave = true,EventID = ActiveEvent.EventID };
break;
case ".CustomControls.SmartParts.Cost":
uiControl = new .CustomControls.SmartParts.CostCenter() { ExternalSave = true};
break;
case ".CustomControls.SmartParts.ReadyTo":
uiControl = new .CustomControls.SmartParts.ReadyToBill(ActiveEvent.EventID) { ExternalSave = true, EventID = ActiveEvent.EventID };
break;
case ".CustomControls.SmartParts.Temporary":
uiControl = new .CustomControls.SmartParts.TemporaryFix() { ExternalSave = true};
break;
case ".CustomControls.SmartParts.RepairFollowup":
uiControl = new .CustomControls.SmartParts.BrakeRepairFollowup() { ExternalSave = true, EventID = ActiveEvent.EventID};
break;
case ".CustomControls.SmartParts.Entry":
uiControl = new .CustomControls.SmartParts.DREntry() { ExternalSave = true };
break;
}
return uiControl;
}
}
}
You can't do this because C# is a statically typed language. The type you want to cast should be known at compile time so the compiler can tread x as Control (or whatever) in the rest of the code.If you could do this:
((controlName)x).Name = "Awesome";
There is no way to know what is the value of controlName or is it a valid type name until runtime.So the type of x can not be determined at compile time which violates the type-safety.
The only exception to static typing in C# is dynamic feature which allows you to declare a variable as dynamic and bypass the compile time checks.You can do any operation and access any member of a dynamic variable at compile time without getting any error.But if you access a member that don't exists you will get a RuntimeBinderException at runtime.
This can be useful in some cases, for example you can create a method that takes string type name as parameter, get the type using Type.GetType method and use Convert.ChangeType method to change type of your object, and assign the result to a dynamic variable. That way you can perform any operation on your dynamic object but you should be careful.BTW,even though this is possible, it is not a preferable way.
I would like to store usersettings. They are created at runtime and should be read after restarting the application.
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
var property = new SettingsProperty("Testname");
property.DefaultValue = "TestValue";
Settings.Default.Properties.Add(property);
Settings.Default.Save();
}
At this point, the setting is stored and I can access it.
After restarting the application, the newly created setting is away:
public MainForm()
{
InitializeComponent();
foreach (SettingsProperty property in Settings.Default.Properties)
{
//Setting which was created on runtime before not existing
}
}
Trying this piece: Settings.Default.Reload(); didn't affect anything on the outcome. I tried also other things like described here, but neither of them worked for me.
Probably a bit late for you but for others there are 2 parts.
Saving the new UserSetting
Reloading from userConfig.xml at startup
I created this extension for ApplicationSettingsBase based on other answers
public static void Add<T>(this ApplicationSettingsBase settings, string propertyName, T val)
{
var p = new SettingsProperty(propertyName)
{
PropertyType = typeof(T),
Provider = settings.Providers["LocalFileSettingsProvider"],
SerializeAs = SettingsSerializeAs.Xml
};
p.Attributes.Add(typeof(UserScopedSettingAttribute), new UserScopedSettingAttribute());
settings.Properties.Add(p);
settings.Reload();
//finally set value with new value if none was loaded from userConfig.xml
var item = settings[propertyName];
if (item == null)
{
settings[propertyName] = val;
settings.Save();
}
}
This will make Settings["MyKey"] work, but when you restart the setting will not be loaded, but the userConfig.xml has the new value (if you called Settings.Save())
The trick to get it to reload is to execute Add again e.g
if (settings.Properties.Cast<SettingsProperty>().All(s => s.Name != propertyName))
{
settings.Add("MyKey", 0);
};
The way Add works is that it will only set MyKey to 0 if no value is loaded from userConfig.xml
Just a tiny bit later:
I was having the same problem now and the answer of Tom was the only functioning hint. But since it was missing a bit of detail I want to share with you my solution for this.
using System.Configuration;
public static class ApplicationSettingsBaseExtension
{
public static void Add<T>(this ApplicationSettingsBase settings, string propertyName, T val)
{
bool itemExists = false;
foreach (SettingsProperty property in settings.Properties)
{
if (property.Name == propertyName)
{
itemExists = true;
break;
}
}
if (!itemExists)
{
var p = new SettingsProperty(propertyName)
{
PropertyType = typeof(T),
Provider = settings.Providers["LocalFileSettingsProvider"],
SerializeAs = SettingsSerializeAs.Xml
};
p.Attributes.Add(typeof(UserScopedSettingAttribute), new UserScopedSettingAttribute());
settings.Properties.Add(p);
settings.Reload();
}
settings[propertyName] = val;
settings.Save();
}
public static T Get<T>(this ApplicationSettingsBase settings, string propertyName, T defaultValue)
{
bool itemExists = false;
foreach (SettingsProperty property in settings.Properties)
{
if (property.Name == propertyName)
{
itemExists = true;
break;
}
}
if (!itemExists)
{
var p = new SettingsProperty(propertyName)
{
PropertyType = typeof(T),
Provider = settings.Providers["LocalFileSettingsProvider"],
SerializeAs = SettingsSerializeAs.Xml
};
p.Attributes.Add(typeof(UserScopedSettingAttribute), new UserScopedSettingAttribute());
settings.Properties.Add(p);
settings.Reload();
}
//finally set value with new value if none was loaded from userConfig.xml
var item = settings[propertyName];
if (item == null)
{
settings[propertyName] = defaultValue;
settings.Save();
}
return (T)settings[propertyName];
}
}
And with that you can use:
Properties.Settings.Default.Add(settingName, settingValue);
Properties.Settings.Default.Save();
...
setting = Settings.Default.Get(settingName, "");
In my case "setting" was a string, but it should work with all base types.
Note that these settings are not included in Settings.Default.Upgrade().
I hope I could help someone.