How to accept input from textbox - c#

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.

Related

RelayCommand is not refreshing execute/canexecute changes

I'm newbee in mvvm (and mvvlight of course). I have 3 modelviews (a MainWindow which have a container, and another 2 modelviews (Login and Menu)). In the LoginModelView, when the user login is successfully, this call the MenuViewModel (With Messenger.Default) changing the page in the MainWindow container. All is alright until that, then i call a Message.Default.Send sending a object from LoginModelView to MenuModelView which is correctly listened, catching the object associed and executing the method associated (ConfiguraMenu) wich define a RelayCommand (checked line by line and the method is executed without any exception) but the problem is this RelayCommand is not working until i back to the LoginViewModel and i login again. I try CommandManager.InvalidateRequerySuggested() and is not working either.
This is the code for the LoginViewModel:
//This method is called when the user press the login button. No problem with this
public void ActionVerificaUsuario()
{
Miusuario = db.getUsuario(Txtusuario, Txtpassword);
if (Miusuario.esUsuario())
{
Messenger.Default.Send(new MoveToViewMessage(Page.MenuView));
Messenger.Default.Send((UsuarioModel)Miusuario);
}
}
This code is for the MenuViewModel:
public RelayCommand AbreExeClaseCommand { get; private set; }
public MenuViewModel()
{
Messenger.Default.Register<UsuarioModel>(this, usuario_recibido => {Miusuario = usuario_recibido;ConfiguraMenu(); });
}
private void ConfiguraMenu() {
Mimenu = new MenuModel(Miusuario);
AbreExeClaseCommand = new RelayCommand(() => { Messenger.Default.Send(new MoveToViewMessage(Page.NeverReachedView)); }, () => Mimenu.Sw_reportes);
CommandManager.InvalidateRequerySuggested();
AbreExeClaseCommand.RaiseCanExecuteChanged();
}
I tried to hardcode the CanExecute with true but the Execute is still without work until back and login again.
I hope you can help me (i'm scratching my head for various days with none result).
MvvmLight provides two different RelayCommand classes in two different namespaces:
Galasoft.MvvmLight.Command
Galasoft.MvvmLight.CommandWpf
Make sure, that you are using the correct namespace Galasoft.MvvmLight.CommandWpf in your WPF application.
There was a bug in MVVMLight, which resulted in not working CanExecute() behavior. They fixed it with the new .CommandWpf namespace in MVVMLight Version V5.0.2.
You can also check out this GalaSoft blog post and the change log for further information.
You try to bind the CanExecute to a propertie.
So my guess is you didn't use RaisePropertie Changed in this propertie.
You must have something like:
public class MenuModel : ViewModelBase
{
// Other pieces of code....
private bool _sw_reportes;
public bool Sw_reportes
{
get { return _sw_reportes; }
set { _sw_reportes = value;
RaisePropertyChanged(() => Sw_reportes); }
}
}

Xamarin Forms - Label, Color and other attribute doesn't update when their Binded attributes are set

I'm comming because I don't understand something about the binding..
I have this attribute in the C# code:
public string MyText { get; set; }
and then in the XAML part:
<Label Text="{Binding MyText}"/>
The first time it works, but if I change MyText string, then the <Label/> doesn't update..
I also saw some post about it, where people speak about INotifyChange or something like that, how does work this Bind? Why the update isn't constant and why it just not work same always?
The problem is that my projet is a bit complex. I have a customCalendar I made by myself which is a Grid "bind by myself again" to a DayCase[6][7] such as Windows calendar, the display is the same.
So my question is double, does I need 1 function by attribute to "listen" if one of them change? Because in the example, I just speak about one Label, but I have 1 label by DayCase, 3 Color to update, a title with Month/Year to update, etc etc
I really lost honestly, I'm sure to know how to think, how to make it..
Thank for your help!
To make binding work. Your ViewModel needs to implement INotifyPropertyChanged, it has an handler public event PropertyChangedEventHandler PropertyChanged, which Xamarin.Forms' binding system to hook up with, and create an invoker for it:
protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
{
var eventHandler = PropertyChanged;
eventHandler?.Invoke(this, e);
}
After that, write your property that to be bind like this:
private string _myText;
public string MyText
{
get { return _myText; }
set
{
if (_myText != value)
{
_myText = value;
OnPropertyChanged(new PropertyChangedEventArgs(nameof(MyText)));
}
}
}
For details, please read https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/data_bindings_to_mvvm/
Also, there are other MVVM frameworks (MvvmCross, Mvvm Light, etc.) or Xamarin.Forms.Lab already did some work for you.
For your customCalendar issue, since to let binding work is to invoke PropertyChanged event, you can write a method to handle this like
public void UpdateDayCase(int i, int j, DayCase)
{
this.DayCases[i][j] = DayCase;
OnPropertyChanged(new PropertyChangedEventArgs(nameof(DayCases)));
}

Should a ViewModel directly reference View objects?

My view has a control inside of it that is capable of generating an image that is saved at a path I can specify (along with some other data). I don't own this control and can't get the interface to generate an image changed. I'm not quite sure how to handle this with MVVM.
The quick and dirty way would be for my view to define a method that takes the desired path, and have the viewmodel call that method.
View:
public void GenerateImage(string path) {
_control.SaveImage(path);
}
ViewModel:
(actually this is the body of a Command) {
var path = GeneratePath();
_view.GenerateImage(path);
...
}
I don't like this because I get the feeling that viewmodels are not meant to directly reference the view, instead they represent the view's state and communicate via property bindings. It works, and I'm doing this while waiting on answers. I'd like to find a way around it.
I could get cute and have the view pass a reference to the control to a Command (I'm in Xamarin Forms) via the Execute() parameter, and have the command cast and make the call. This seems like lipstick on a pig since it makes the viewmodel still aware of a particular class inside the view. But in writing this paragraph I think I came up with a solution I like.
I /could/ create:
interface IGenerateImage {
void GenerateImage(string path);
}
The obvious implementation would delegate the call to an encapsulated control. I feel like if the view passes an IGenerateImage then I'm not creating the viewmodel-to-view dependency that I'm trying to avoid, and I can test the logic without needing to instantiate expensive UI classes.
I like that answer, but I'm pretty sure there's an obvious solution I'm missing. Is there some other useful pattern for handling it? Or is it not a big deal if the viewmodel references the view?
You never want the View Model to know anything about the View.
It's a little unclear what you can and can't change in your post, so I'm assuming you can change the V/VM, but not _control.
The easiest way is to create an event in the View Model that the View can subscribe to.
Something like this:
View:
// Constructor
public View()
{
// However you're setting your VM, i.e. DI or new-ing up the VM
// Subscribe to the event
vm.ImageGeneratedEvent += this.OnImageGeneratedEvent;
}
private void OnImageGeneratedEvent(object sender, ImageGeneratedEventArgs args)
{
// Call your SaveImage in the event handler
_control.SaveImage(args.Path);
}
View Model:
public event EventHandler<ImageGeneratedEventArgs> ImageGeneratedEvent;
// Command body
{
var path = GeneratePath();
// Send event to the View
this.NotifyImageGeneratedEvent(path)
}
private void NotifyImageGeneratedEvent(string path)
{
ImageGeneratedEventArgs args = new ImageGeneratedEventArgs(path);
if (this.ImageGeneratedEvent!= null)
{
this.ImageGeneratedEvent(this, args);
}
}
ImageGeneratedEventArgs:
public class ImageGeneratedEventArgs : EventArgs
{
public string Path { get; set; }
public ImageGeneratedEventArgs(string path)
{
this.Path = path;
}
}

.net ASCX help with passining info & Hiding Div

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.

Passing information back from a UserControl

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.

Categories

Resources