locked
MVVM Problem RRS feed

  • Question

  • User394276 posted

    Hello I have a little problem with my code

    <Button Text="Registrame" x:Name="btn_registramen" Style="{StaticResource YellowButtons}" Margin="0,20,0,0" Command="{Binding LoginCommand}}" > <Button.CommandParameter> <model:User/> </Button.CommandParameter> </Button>

    I have a button, where I want to pass data, but the problem comes, when I put the LoginViewModel as a binding context

    ``` class LoginViewModel {

        public LoginCommand LoginCommand { get; set; }
        public User User { get; set; }
    
        public LoginViewModel(User user) {
    
            LoginCommand = new LoginCommand(this);
            User = user;
        }
    
        internal async void SendData(object obj) {
    
            await Application.Current.MainPage.Navigation.PushAsync(new LoginScreen());
        }
    }
    

    ```

    Appently Xaml dosent like constructors with something inside

    Missing default constructor for"

    Monday, June 1, 2020 10:08 AM

Answers

  • User390529 posted

    Try this...

    • Marked as answer by Anonymous Thursday, June 3, 2021 12:00 AM
    Wednesday, June 10, 2020 1:28 AM

All replies

  • User288194 posted
    1. What is LoginCommand ?
    2. Your command should be pointing to the method that will execute, like: LoginCommand = new LoginCommand(() => SendData);
    3. You should define a command that take parameters if you want to send parameters.
    4. Read some documentation: MVVM Pattern in Xamarin.Forms, The Xamarin.Forms Command Interface
    Monday, June 1, 2020 7:03 PM
  • User394276 posted
    1. Login command is a command defined on a class that implement the Icommand Interface, where I received the LoginVewModel as a parameter
    2. The login command is working perfectly, the problem is, where do I initialize my user, I was trying to passing through parameter to my view model, but xaml dosent like it

    I try to initialize my login view model in an entryTextChage, just to confirm that I get my data (that I get), but obviously I dont when to have that there

    Monday, June 1, 2020 7:21 PM
  • User394276 posted

    I will make an example to illustrate what I was trying to do

    https://pastebin.com/GALp791b

    something like this is what I am trying to do

    I am very new to mvvm

    Monday, June 1, 2020 7:24 PM
  • User369979 posted

    I don't know why you want to define an extra LoginCommand here. But a normal command could fit your situation:

    public class LoginViewModel
    {
    
        public ICommand LoginCommand { get; set; }
        public User User { get; set; }
    
        public LoginViewModel(User user)
        {
    
            LoginCommand = new Command((singleUser) =>
            {
                // We could get the desired object from binding
            });
            User = user;
        }
    
        internal async void SendData(object obj)
        {
    
            await Application.Current.MainPage.Navigation.PushAsync(new LoginScreen());
        }
    } 
    

    CommandParameter will be passed into your command's initialization. We shouldn't reassign it to this.

    Tuesday, June 2, 2020 2:24 AM
  • User394276 posted

    The problem in in the front end, the page Xaml do not like that veiw model, becouse, we are passing something in the contructor

    ``` Error XLS0507 Type 'RegisterViewModel' is not usable as an object element because it is not public or does not define

    <StackLayout>
        <Entry Placeholder="Username"
               Text="{Binding username, Source={StaticResource model}}" />
        <Entry Placeholder="Password"
               Text="{Binding password, Source={StaticResource model}}"/>
        <Button BackgroundColor="DarkCyan" Command="{Binding RegisterCommand, Source={StaticResource RegisteVM}}" >
            <Button.CommandParameter>
                <model:User/>
            </Button.CommandParameter>
        </Button>
    </StackLayout>
    

    ```

    Tuesday, June 2, 2020 3:38 AM
  • User369979 posted

    What problem are you facing? The command parameter or this RegisterViewModel? If you want to know why you can't initialize this RegisterViewModel in xaml try to post the constructor of this model here.

    Tuesday, June 2, 2020 5:45 AM
  • User394276 posted

    Hello my friend thank you very much, for taking the time to address my concerns, I hope that you are staying safe. I also have some questions.

    1. What is the difference between the model and the viewmodel, becouse to make this work, I can define a string string username string password in my vewmodel and bind my view components with my view model. This solution will also work.
    2. Someone told me that I should use MVVM, if I plan to do Unit Test, otherwise I can stick with code behind
    3. You asked me why I am using this in my Command, I am following my teacher https://youtu.be/fOookEq5od0
    4. this is my registerVM ``` public ICommand RegisterCommand { get; set; } public User User { get; set; }

      public RegisterViewModel(User user) {
      
          RegisterCommand = new Command(someMethod);
          User = User;
      }
      
      internal void SendData(object data) {
      
      
      }
      
      public void someMethod() {
      

    5. How can I disable the button on my xaml if my user is null 6. my xaml still give me errors

    <ContentPage.Resources>
        <vm:RegisterViewModel x:Key="myVM" /> // RegisterViewModel' is not usable as an object element because it is not public or does not define a public parameterless constructor or a type converter.
    
    </ContentPage.Resources>
    
    <StackLayout>
        <Entry Placeholder="Username" x:Name="username"
               Text="{Binding username}" />
        <Entry Placeholder="Password" x:Name="pass"
               Text="{Binding password}"/>
        <Button BackgroundColor="DarkCyan"
                Command="{Binding RegisterCommand}"
                Text="Register">
        </Button>
    </StackLayout>
    

    ```

    Tuesday, June 2, 2020 6:52 PM
  • User381156 posted

    That video is a bit misleading. Check out this one instead: https://channel9.msdn.com/Series/Xamarin-101/XamarinForms-MVVM-with-XAML-6-of-11

    Wednesday, June 3, 2020 12:57 PM
  • User394276 posted

    Thank you so much, I still have a question, regarding the app on the video.

    The properties of The note class are being defined in the MainPageViewModel, so what is the difference between the model and the viewmodel

    Thursday, June 4, 2020 2:42 AM
  • User394276 posted

    This is my VM

    ``` public class RegisterViewModel {

        public ICommand RegisterCommand { get; set; }
        public User User { get; set; }
    
        public RegisterViewModel() {
    
            RegisterCommand = new Command(SendData);
        }
    
        internal void SendData(object data) {
    
            data = User;
    
    
        }
    

    } ```

    I have my class

    ``` public class User : INotifyPropertyChanged {

        private string _username;
        public string username {
            get { return _username; }
            set {
                if (_username != value) {
                    _username = value;
                    RaisePropertyChanged();
                }
            }
        }
    
    
        private string _password;
        public string password {
            get { return _password; }
            set {
                if (_password != value) {
                    _password = value;
                    RaisePropertyChanged();
                }
            }
        }
    
        public User() {
    
        }
    
    
    
    
        #region Notify Property Changed Members
        public event PropertyChangedEventHandler PropertyChanged;
        private void RaisePropertyChanged([CallerMemberName] string propertyName = "") {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        #endregion
    }
    

    } ```

    and my xaml

    <ContentPage.Resources>
        <vm:RegisterViewModel x:Key="VM" />
    </ContentPage.Resources>
    <StackLayout>
        <Entry Placeholder="Username" x:Name="username"
               Text="{Binding username}" />
        <Entry Placeholder="Password" x:Name="pass"
               Text="{Binding password}"/>
        <Button BackgroundColor="DarkCyan"
                Command="{Binding RegisterCommand}"
                CommandParameter="{Binding}"
                Text="Register">
        </Button>
    </StackLayout>
    

    ```

    I also want to know how to disable the button, when I don't have values

    Thursday, June 4, 2020 2:58 AM
  • User369979 posted

    This xaml won't work for binding. It only defines a view model in the resource but you haven't applied it to your page so that your controls won't know which binding context it needs to consume for binding. I didn't watch the videos you posted. But if you want to know more about MVVM, try to refer to our official documentation: https://docs.microsoft.com/en-us/xamarin/xamarin-forms/xaml/xaml-basics/data-bindings-to-mvvm

    What is the difference between the model and the viewmodel View model is the page's binding context which contains what components could be used for binding in xalm. And model indicates your data components. i.e. If you retrieve data from the database we need a c# class model to make the data readable. I also want to know how to disable the button, when I don't have values Command contains a canexecute parameter which reveals whether this command could be triggered: https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/data-binding/commanding If you bind your button to command with canexecute to false, this button is disabled.

    Thursday, June 4, 2020 3:13 AM
  • User394276 posted

    May I ask why it would not bind? in my code behind I put

    RegisterViewModel registerViewModel = new RegisterViewModel(); BindingContext = registerViewModel;

    and on the video of channel 9 provided by @MREme, they are doing it in xaml and for me in dosent work

    Thursday, June 4, 2020 3:27 AM
  • User369979 posted

    If you have implemented it with code behind and then it will work. But you didn't mention it before so I said it doesn't work if you only consume:

    <ContentPage.Resources>
        <vm:RegisterViewModel x:Key="VM" />
    </ContentPage.Resources>
    

    However, we could achieve this in xaml like:

    <ContentPage.BindingContext>
            <vm:RegisterViewModel />
    </ContentPage.BindingContext>
    
    Thursday, June 4, 2020 3:41 AM
  • User394276 posted

    OMG It finally worked thank you so much.

    How do I retrieve the username and password

    <StackLayout> <Entry Text="{Binding User.username, Mode=TwoWay}" /> <Entry Text="{Binding User.password, Mode=TwoWay}" /> <Button Command="{Binding RegisterCommand}" /> </StackLayout>

    and disable my button

    If I put breakpoints, my user is still null

    I have a question, what is the difference about creating a command like my video, and the technique that they use in Xamarin 101 in youtube

    Thursday, June 4, 2020 3:56 AM
  • User369979 posted

    This is because you didn't pass the command parameters. Try to bind the command like:

    <Button Command="{Binding RegisterCommand }" CommandParameter="{Binding User}"/>
    

    And if you want to disable the button:

    RegisterCommand = new Command(SendData, (model) => isEnabled);
    

    Define a isEnabled in your view model to determine whether the command is enabled. Moreover, I noticed that your SendData assigns an existed property to the parameter. We won't make it like this. parameter often occurs at the right side of "=":

    internal void SendData(object data)
    {
        var model = data as User;
    }
    

    I tried to make a sample for you. The second button disables the first button in the view model: However, I think you need to read these documentations more precisely to know more about MVVC: https://docs.microsoft.com/en-us/xamarin/xamarin-forms/xaml/xaml-basics/data-bindings-to-mvvm https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/data-binding/commanding

    Thursday, June 4, 2020 6:00 AM
  • User394276 posted

    The only thing that is confuse in the docs, is that this

    ```

        public DateTime DateTime
        {
            set
            {
                if (dateTime != value)
                {
                    dateTime = value;
    
                    if (PropertyChanged != null)
                    {
                        PropertyChanged(this, new PropertyChangedEventArgs("DateTime"));
                    }
                }
            }
            get
            {
                return dateTime;
            }
        }
    }
    

    } ```

    So he we are defining the data time in a viewModel, so why would be need a class for?

    for example in the xamarin 101 course on youtube, he declares evrery property in the viewModel, so uf he is declaring everything in the view model, why do I need a class.

    for Instance, if I follow the docs

    ```

        private string _username;
        public string username {
            get { return _username; }
            set {
                if (_username != value) {
                    _username = value;
                    RaisePropertyChanged();
                }
            }
        }
    
    
        private string _password;
        public string password {
            get { return _password; }
            set {
                if (_password != value) {
                    _password = value;
                    RaisePropertyChanged();
                }
            }
        }
    
        public User() {
    
        }public RegisterViewModel() {
    
            RegisterCommand = new Command(SendData);
        }
    
        #region Notify Property Changed Members
        public event PropertyChangedEventHandler PropertyChanged;
        private void RaisePropertyChanged([CallerMemberName] string propertyName = "") {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        #endregion
    

    ```

    and if I do this, this will work, so what is the purpose of the class

    Thursday, June 4, 2020 7:29 AM
  • User369979 posted

    It all depends on your own requirements. Someone needs a list to display a set of data so they need a class. Someone needs a complicated data so they need a class. It all depends.

    Thursday, June 4, 2020 7:32 AM
  • User394276 posted

    oh ok so in mvvm, the class is not mandatory

    Thursday, June 4, 2020 7:34 AM
  • User369979 posted

    Yes. We could use a simple list like List<sting>. It doesn't require a model class. It depends on the structure of your data.

    Thursday, June 4, 2020 7:39 AM
  • User394276 posted

    I was trying to replicate your sample (Thanks)

    but I still cannot get my user in the binding

    and becouse you put everything in the code-behing, you have access to the isEnable

    but what if I wand to disable the button on my View Model? ``` public ICommand RegisterCommand { get; set; } public User User { get; set; }

        public RegisterViewModel() {
    
            RegisterCommand = new Command(SendData);
        }
    
        internal void SendData(object data) {
    
            User = new User();
    
    
        }
    
        public void someMethod() {
    
        }
    }
    

    ```

    Also what is the deference between the way old way of using Icommand (my video ) and the new way (xamarin 101)

    Thursday, June 4, 2020 7:46 AM
  • User394276 posted

    You have been great help, thank you, and U am sorry if I take too much of you time with stupid questions

    Thursday, June 4, 2020 7:47 AM
  • User369979 posted

    I really can't fully understand what you want to achieve. isEnable is a field located in the view model and you could replace it with any other conditions you want. The user property hasn't implemented the INotifyPropertyChanged interface so the xaml won't be notified even if its value has been changed.

    Thursday, June 4, 2020 7:52 AM
  • User394276 posted

    What I am trying to achieve is making a class named User (username and password) and making a button and the button cannot be clicked until those are not null or empty

    Thursday, June 4, 2020 8:15 AM
  • User394276 posted

    ``` public ICommand RegisterCommand { get; set; } public User User { get; set; } public bool isEnabled = false;

        public RegisterViewModel() {
    
            RegisterCommand = new Command(SendData, (model) => isEnabled);
        }
    
        internal void SendData(object data) {
    
            data = User as User;
    
            if (data != null) {
    
                isEnabled = true;
                ((Command)RegisterCommand).ChangeCanExecute();
    
            }
    

    } ```

    cannot get it to work, but there is a solution without using a lamda expression (I do not like to use things that I do not understand)

    Thursday, June 4, 2020 8:43 AM
  • User369979 posted

    Did you assign the parameter:

    <Button Command="{Binding RegisterCommand }" CommandParameter="{Binding User}"/>
    

    cannot get it to work, but there is a solution without using a lamda expression You need to get used to it. Lambda is used very frequently in c#.

    Friday, June 5, 2020 9:23 AM
  • User394276 posted

    yes I am

    <StackLayout> <Entry Text="{Binding User.username, Mode=TwoWay}" /> <Entry Text="{Binding User.password, Mode=TwoWay}" /> <Button Command="{Binding RegisterCommand}" Text="efjcfreowpqdkfweqpdk" BackgroundColor="Chartreuse" CommandParameter="{Binding User}"/> </StackLayout> and I still cannot find that my button becomes enable when my Entry are not empy

    Friday, June 5, 2020 3:38 PM
  • User394276 posted

    ok so I am passing the username and password but i am still unable to check if my textbox are empty and enable it when is not empty

    ``` public ICommand RegisterCommand { get; set; } public User User { get; set; }

        private bool _isEanble;
        public bool isEanble {
            get { return _isEanble; }
            set {
                if (_isEanble != value) {
                    _isEanble = value;
                    RaisePropertyChanged();
                }
            }
        }
    
        public RegisterViewModel() {
    
            RegisterCommand = new Command(SendData, isEnabled);
            User = new User();
        }
        private bool isEnabled(object arg) {
            return _isEanble;
        }
    
        internal void SendData(object data) {
    
            data = User as User;
    
            if (data != null) {
    
                _isEanble = true;
                ((Command)RegisterCommand).ChangeCanExecute();
    
            }
        }
    
    
        #region Notify Property Changed Members
        public event PropertyChangedEventHandler PropertyChanged;
        private void RaisePropertyChanged([CallerMemberName] string propertyName = "") {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        #endregion
    
    
    }
    

    ```

    Sunday, June 7, 2020 3:03 AM
  • User381156 posted

    I think you are confusing the "Command" of the Button with the "IsEnabled" property of the Button. They are two separate things. The Command is used when the user Clicks the button, this will trigger the Command action defined in the bound View Model.

    Enable/Disable of the Button is controlled by toggling the IsEnabled property of the Button. If you want the Button to Enable/Disable when the user begins to type you would want to look at the TextChanged event of the Entry box and change the IsEnabled property of the Button when the text changes in the Entry box:

    https://docs.microsoft.com/en-us/dotnet/api/xamarin.forms.inputview.textchanged?view=xamarin-forms

    And this (which will be necessary if you want to keep most of the code in the view model for MVVM): https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/behaviors/reusable/event-to-command-behavior

    An alternative to this would be to implement some validation on the User object directly which would again toggle the isEnabled property of the view model (which should be bound to the button's IsEnabled property): https://www.davidbritch.com/2017/03/validating-user-input-in-xamarinforms.html

    Also, I also recommend studying up on Lambda as it will save you a ton of time.

    Sunday, June 7, 2020 4:20 AM
  • User394276 posted

    @MREme Yes I am implementing this, and it works, but I am implementing this in code-behind, but if you see this video https://youtu.be/rv9flLl9Hrc (is the same video).

    The CommandParameter button of the video, is disable until is filled

    Sunday, June 7, 2020 4:47 AM
  • User390529 posted

    Try this...

    • Marked as answer by Anonymous Thursday, June 3, 2021 12:00 AM
    Wednesday, June 10, 2020 1:28 AM
  • User394276 posted

    This works fine, but Can you explain me some things

    • Where is the model
    • What is the difference between your code and mine
    • In the video that I posted, for that guy is working why, what did i do wrong
    Wednesday, June 10, 2020 1:40 AM
  • User390529 posted

    @edyboy said: This works fine, but Can you explain me some things

    • Where is the model Hi, I don´t use model (User), I use property (User and Password)

    • What is the difference between your code and mine I don´t know, because for me your code is very confusion, I make my own style.

    • In the video that I posted, for that guy is working why, what did i do wrong I don´t know.

    ** I'm still learning English yet, I write like a baby... :wink:

    Wednesday, June 10, 2020 4:24 PM
  • User390529 posted

    Send me your complete code and I look it.

    Wednesday, June 10, 2020 4:32 PM
  • User394276 posted

    voy espera

    Friday, June 12, 2020 1:44 AM