I am just getting to grips with the concept of a UserControl.
I've created a UserControl to group together a number of controls that were being duplicated on individual pages of a TabControl.
Some of these controls are text fields that require validation, and when validation is unsuccessful I need to display an error message. However the place where I want to display the error message is on the status bar on the main form.
What is the best way to handle validation/error display in this situation?
To handle validation do one of these:
Validate with a method inside the user control
Have your user control have a delegate property (e.g. ValidationHandler) that can handle the validation (this would allow you to have a class with a bunch of validators that you could assign to your controls)
public delegate void Validator(...)
public Validator ValidationHandler { get; set; }
Have your user control generate a validation request event (e.g. ValidationRequested)
public event EventHandler<ValidationEventArgs> ValidationRequested
To notify the system that an error has occurred do one of these:
Use an event that interested parties can subscribe to (e.g. ValidationFailed)
If the object that performs the validation (via the delegate or event) is also the one that you want to generate the error message from, it can raise the error message itself.
EDIT:
Since you've said you would validate inside your control, the code for a ValidationFailed event might look like:
// In your user control
public class ValidationFailedEventArgs : EventArgs
{
public ValidationFailedEventArgs(string message)
{
this.Message = message;
}
public string Message { get; set; }
}
private EventHandler<ValidationFailedEventArgs> _validationFailed;
public event EventHandler<ValidationFailedEventArgs> ValidationFailed
{
add { _validationFailed += value; }
remove { _validationFailed -= value; }
}
protected void OnValidationFailed(ValidationFailedEventArgs e)
{
if(_validationFailed != null)
_validationFailed(this, e);
}
private void YourValidator()
{
if(!valid)
{
ValidationFailedEventArgs args =
new ValidationFailedEventArgs("Your Message");
OnValidationFailed(args);
}
}
// In your main form:
userControl.ValidationFailed +=
new EventHandler<ValidationFailedEventArgs>(userControl_ValidationFailed);
// ...
private void userControl_ValidationFailed(object sender,
ValidationFailedEventArgs e)
{
statusBar.Text = e.Message;
}
If you're doing the validation in the UserControl, you can have it offer a public ValidationFailed event and include the message in the EventArgs. The parent control could then subscribe to the ValidationFailed event and update the status bar.
You can either put a validator on the user control itself, throw an exception, or add public getters to the fields you want shown in the parent form.
Make a public method on your usercontrol that validates its field, and you can pass in a string output parameter.
so something like
public bool IsValid(out string status)
{
// do validation and set the status message
}
You can use asp.net validators in the user controls, and a validation summary on the main form and it will list the errors for you.
For other type of uses, you can expose an event, and have the page that contains the control subscribe to the event and take whatever action necessary.
Related
using xamarin forms & PCL.
i want to validate the Picker using the Behavior to ensure that user picked an item from the Picker.
my behavior class is
public class PickerValidationBehaviour :Behavior<Picker>
{
private Picker _associatedObject;
public string PropertyName { get; set; }
protected override void OnAttachedTo(Picker bindable)
{
base.OnAttachedTo(bindable);
_associatedObject = bindable;
if (_associatedObject.SelectedIndex < 0 )
{
HandleValidation();
}
}
private void HandleValidation()
{
}
private void _associatedObject_SelectedIndexChanged(object sender, EventArgs e)
{
}
protected override void OnDetachingFrom(Picker bindable)
{
base.OnDetachingFrom(bindable);
_associatedObject = null;
}
}
}
and i was stuck because i want execute the validation before user action, such that the submit button will be hidden until the user fill the form.
and beside if there is any easy efficient way that i can perform the validation please mention it.
I think this scenario you should put logic in VM instead of using behavior.
Cause behavior can change some UI element, like color something and most of them are the element itself's property.
In your case, you want to change another element in Page. There is a problem, how to access another element in your page.
If you binding SelectedIndex in you VM, and when property changed you can raise another property which controls the submit button. That will be easier then do it in behavior.
I have a program that connects to a server and sends commands to it.
in my program I have 2 windows, one of them is a toolbar with a textbox that shows current status (we'll call that "mainviewmodel") and the other is a login window which receives username and password and logs me into the server (we'll call that "loginviewmodel")
now, in order for the mainviewmodel to know the loginviewmodel I use this:
[Import]
Private LoginViewModel loginViewModel;
lunch the login window from the mainviewmodel I have the following function:
public void Login()
{
if (!loginViewModel.CanInvokeLogin)
return;
if (loginViewModel.IsActive)
{
loginViewModel.Focus();
}
else
{
windowManager.ShowWindow(loginViewModel);
}
}
as you can see - I have in loginviewmodel a property named CanInvokeLogin which indicates if login is in progress or not.
on mainviewmodel I have a property that shows me current client status (binded to the view's textbox)
public string TextboxDescription
{
get
{
switch (AvailabilityStatus.Type)
{
case AvailabilityStatusType.READY:
return ("Ready");
case AvailabilityStatusType.BREAK:
return (AvailabilityStatus.Reason);
case AvailabilityStatusType.DISCONNECTED:
if (!loginViewModel.CanInvokeLogin)
{
return ("Conencting");
}
return ("connected");
default:
return ("Please wait...");
}
}
}
}
My problem is - the status would not be updated on the view unless
NotifyOfPropertyChange(() => TextboxDescription);
is being called, so I need to call it whenever
NotifyOfPropertyChange(() => CanInvokeLogin);
is being called, but that happens on a different viewmodel.
so, how can I notify the mainviewmodel that caninvokelogin have been changed?
I know I could use eventAggregator and send a message from one viewmodel to another, but it sounds like killing a fly with a cannon and I bet there's a simpler way,
any suggestions?
Handle The Property Changed Event
The PropertyChanged event is simply an event so there is nothing stopping you from listening to that event from another view model if that is what you need.
this.loginViewModel.PropertyChanged += this.OnLoginPropertyChanged;
The event handler method would look something like this...
private void OnLoginPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "TextboxDescription") {
// Do something.
}
}
Raise StatusChanged Events:
To be honest if I was implementing this myself I would simply be firing events from the LoginViewModel when the status changed and then handling those events instead, seems like a cleaner solution to this.
this.loginViewModel.StatusChanged += this.OnLoginStatusChanged;
private void OnLoginStatusChanged(object sender, LoginStatusChangedEventArgs e)
{
// Do something.
switch (e.StatusType)
{
...
}
}
I would have custom event args like so...
public class LoginStatusChangedEventArgs : EventArgs
{
public AvailabilityStatusType StatusType { get; set; }
}
Just fire this event when the status changes and listeners can handle that.
Event Aggregator:
You could also use the event aggregator however unless you have lots of disconnected classes that need to listen to this I would probably feel it was overkill.
this.eventAggregator.Publish(new LoginStatusChangedMessage(AvailabilityStatusType.Disconnected));
I am attempting to implement a model view presenter pattern in C# windows forms. I have tried several different methods but have not figured this out. Is there anyway to "accept" user input from a text box when the user clicks off of the text box? If there is not, what is the typical way to pass data to the presenter? I can use the textbox's on_text_changed event but then I am confused on how to validate the data.
I think its easy here are the MSDN links that illustrate the function of TextBox class with code.
TextBoxBase.Text Property
& validate using:
Control.Validated Event
Hope it helps!
I know this thread is a way too old but still.
public interface IProjectView
{
string textBoxText{get;}
}
implement it in ProjectView
public class ProjectView : IProjectView
{
ProjectPresenter _presenter;
public ProjectView()
{
_presenter = new ProjectPresenter(this);
}
string textBoxText
{
get
{
// Do validation if you want
return textBox1.Text;
}
}
}
class ProjectPresenter
{
IProjectView _view;
public ProjectPresenter(IProjectView view)
{
_view = view;
}
public void AnyMethod()
{
// Access value of textbox as _view.txtTextBoxText
}
}
Code not tested, but should work fine.
Regarding validation, while implementing the property in ProjectView, do the validation before returning value.
You'll want to listen for the Leave event. That'll happen when the textbox loses focus; after that, you can do your validation.
Alright, I am trying to accomplish this: When a user clicks a button that is on a ascx web user control with text boses, it first displays a DIV that is hidden, this div contains a ascx web user control. Basically I want that web user control to grab what they typed in the boxes on the first web user control, and then apply to a SQL search from what the users type in the text boxes on the first page. Is this possible or do I need to rethink my strategy on this? I am programming in c# for the SQL statements.
It is possible.
You can define properties of the control which accepts the text input, and expose the values using direct field access, variables, or session variables; you can then use FindControl from within the newly displayed control, and, if found, utilise the now exposed properties to gather the values required.
For instance, your input control code-behind might look something like this:
partial class MyControl : UserControl
{
public string MyFieldValue
{
get { return MyFieldTextBox.Text; }
}
}
And in the next control, to use it, a little like this:
partial class MyControl : UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
var myControl = Page.FindControl("MyControlInstanceName") as MyControl;
if (myControl != null)
{
var myFieldValue = myControl.MyFieldValue;
}
}
}
Is the 2nd user control embedded in the 1st or not?
If not, you can make anything available upwards between user controls by simply adding public properties to your user controls. This means they can then be accessed from the page level or the containing user control. For example, if I have UCA, UCB, UCC
UCA contains UCB and UCC is hidden.
UCB has the following property
public string UserEnteredName
{
get { return NameTextBox.Text; }
}
UCC has the following property and method
public string UserEnteredName { get; set; }
public BindResults()
{
UserEnteredLiteral.Text = UserEnteredName;
}
Then tie it together with UCA:
protected MyButton_Click(object sender, EventArgs e)
{
UCC.UserEnteredName = UCB.UserEnteredName;
... some logic herre.
UCC.BindResults();
}
You can also raise an event from UCB that can be responded to in UCA if your button or submit action exists in UCB.
How can I pass user control properties to the page AND make these properties available to all methods on the page (and not just to one method that is fired on a control action, e.g. onControlClick)
I have a set up of essentially 3 pages:
user control (ascx/cs)
class (cs) - that contains user control properties
host page (aspx/cs) - references the user control
The user control consists of 3 interrelated dropdowns. I'm having success passing these dropdown values through a class onto the page via an event that is fired when a user clicks on the dropdown menu. So this way the host page is continously aware of the values in the user control. However, I want the page to use the control's properties (stored in a class) on all of its methods - how do I make this user control class available to all?
Also I'm using ASP.NET and C# by the way.
Here's the Code (not sharing the full code here - just the snippets of a similar code block)
On the ASPX for Menu Host Page:
<linked:LinkMenu2 id="Menu1" runat="server" OnLinkClicked="LinkClicked" />
Host Page (cs):
protected void dropdownclicked(object sender, ddtestEventArgs e)
{
if (e.Url == "Menu2Host.aspx?product=Furniture")
{
lblClick.Text = "This link is not allowed.";
e.Cancel = true;
}
else
{
// Allow the redirect, and don't make any changes to the URL.
}
}
Host Page (aspx)
<asp:dropdowncustom ID="dddone" runat="server" OnddAppClicked="dropdownclicked" />
Control (cs)
public partial class usercontrol_tests_dropdown1 : System.Web.UI.UserControl
{
public event ddtestEventHandler ddAppClicked;
}
public void selectapp_SelectedIndexChanged(object sender, EventArgs e)
{
ddtestEventArgs args = new ddtestEventArgs(selectlink.SelectedValue);
ddAppClicked(this, args);
}
Class:
public class ddtestEventArgs : EventArgs
{
// Link
private string link;
public string Link
{
get { return link; }
set { link = value; }
}
public ddtestEventArgs(string link)
{
Link = link;
}
}
public delegate void ddtestEventHandler(object sender, ddtestEventArgs e);
Hopefully this is what you're after. The best way to do it is to expose your controls as public properties from your user control. So, in your user control, for each drop down list add a property:
public DropDownList DropDown1
{
get { return dropDownList1; }
}
public DropDownList DropDown2
{
get { return dropDownList2; }
}
You can do the same for any other properties you want to access on the host page:
public string DropDown1SelectedValue
{
get { return dropDownList1.SelectedValue; }
set { dropDownList1.SelectedValue = value; }
}
Then, from your host page you can access the properties through the user control:
string value = UserControl1.DropDown1SelectedValue;
or
string value = UserControl1.DropDownList1.SelectedValue;
Here's a couple of other answered questions that you might find useful as I think (if I've understood correctly) this is what you're doing:
Getting data from child controls loaded programmatically
How to change the value of a control in a MasterPage.