MVVM bindowanie do labela i textboxów

0

Powoli uczę się MVVMa w Wpfie...konkretnie mam problem z ładowaniem zawartości dwóch textboxów do kontrolki Label i Messagebox. Po kompilacji MessageBox wyskakuje ale bez wpisanej zawartności z textboxów.
Poniżej kod:

Person.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.ComponentModel;
using System.Text;
using System.Threading.Tasks;

namespace NextMVVM.Model
{
    public class Person : INotifyPropertyChanged
    {
        private string _Imie;
        public string Imie
        {
            get { return _Imie; }
            set { _Imie = value;
                OnPropertyChanged("Imie");
                
            }
        }

        private string _Nazwisko;
        public string Nazwisko
        {
            get { return _Nazwisko; }
            set { _Nazwisko = value;
                OnPropertyChanged("Nazwisko");
                
            }
        }

        private string _FullName;
        public string FullName
        {
            get { return _FullName = Imie + " " + Nazwisko; }
            set
            {
                if (_FullName != value)
                {
                    _FullName = value;
                    OnPropertyChanged("FullName");
                }


                    }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;

            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

    }
}


PersonViewModel

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using NextMVVM.Model;
using System.Windows.Input;
using NextMVVM.Command;
using System.Windows;

namespace NextMVVM.ViewModel
{
    public class PersonViewModel : INotifyPropertyChanged
    {
        private Person _Person;
        public Person Person
        {
            get { return _Person; }
            set
            {
                _Person = value;
                OnPropertyChanged("Person");
            }
        }

        public ICommand Content { get { return new RelayCommand(execute, canexecute); } }
        

        private bool canexecute(object parameter)
        {
            return true;
        }

        private void execute(object parameter)
        {
            Person Person = new Person();
            string.Format("{0} jest OK", Person.FullName);
            MessageBox.Show("Witaj " + Person.FullName);
            
        }



        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;

            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}


RelayCommand

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;

namespace NextMVVM.Command
{
    public class RelayCommand : ICommand
    {

        Action<object> _execute;
        Func<object, bool> _canexecute;
        public RelayCommand(Action<object> execute, Func<object, bool> canexecute)
        {
            _execute = execute;
            _canexecute = canexecute;

        }
        public bool CanExecute(object parameter)
        {
            if (_canexecute != null)
            {
                return _canexecute(parameter);
            }
            else
            {
                return false;
            }
        }

        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }

        public void Execute(object parameter)
        {
            _execute(parameter);
        }
    }
}


MainWindow.xaml

<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:NextMVVM"
        xmlns:ViewModel="clr-namespace:NextMVVM.ViewModel" x:Class="NextMVVM.MainWindow"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    

    <Grid>
        <TextBox x:Name="textBox" Text="{Binding Person.Imie, Mode=TwoWay}" HorizontalAlignment="Left" Height="23" Margin="86,55,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
        <TextBox x:Name="textBox1" Text="{Binding Person.Nazwisko, Mode=TwoWay}" HorizontalAlignment="Left" Height="23" Margin="86,92,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
        <Label x:Name="label" Content="{Binding Person.FullName}" HorizontalAlignment="Left" Margin="266,92,0,0" VerticalAlignment="Top"/>
        <Button x:Name="button" Content="Pokaż" Command="{Binding Content}" HorizontalAlignment="Left" Margin="86,136,0,0" VerticalAlignment="Top" Width="75"/>
        <TextBox x:Name="textBox2" HorizontalAlignment="Left" Height="23" Margin="86,208,0,0" TextWrapping="Wrap" Text="{Binding Person.FullName, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="120"/>

    </Grid>
</Window>


MainWindow.cs

using NextMVVM.ViewModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;


namespace NextMVVM
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = new PersonViewModel();
        }
    }
}


1

W metodzie execute tworzysz sobie nową, pustą osobę: Person Person = new Person();, zamiast odwoływać się do tej, którą masz jako właściwość w swoim ViewModel.

0

Racja, ale teraz wyrzuca NullReferenceException przy metodzie > execute

2

To zrób: Person = new Person(), aby utworzyć nowy obiekt w konstruktorze swojego PersonViewModel :)

0

Też pokazuje się pusty MessageBox :(
Datacontext mam dobrze ustawiony? Może coś z klasą Person.cs?
Już nie mam pomysłu gdzie może być błąd

0

Jeżeli metoda Execute() się wywołuje to ViewModel jest podpięty. Pokaż teraz ten kod ViewModelu po zmianach zasugerowanych przez @Ktos . Postaw sobie breakpoint'a na setterze Person i zobacz czy coś się dzieje. Kolejna sprawa nie rozumiem podejścia w RelayCommand, ponieważ obecna forma wymusza byś pisał takie cuda jak:

private bool canexecute(object parameter)
{
       return true;
}

Wystarczy dodać domyślną wartośc null drugiego parametru konstruktora w RelayCommand oraz zmodyfikować tam metodę CanExecute(), by uniknąć nadmiarowego pisania CanExecute do każdej komendy.

0

Postawiłem i wychodzi wartość null :/
Kod ViewModelu:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using NextMVVM.Model;
using System.Windows.Input;
using NextMVVM.Command;
using System.Windows;

namespace NextMVVM.ViewModel
{
    public class PersonViewModel : INotifyPropertyChanged
    {
        private Person _Person;
        public Person Person
        {
            get { return _Person; }
            set
            {
                _Person = value;
                OnPropertyChanged("Person");
            }
        }

        public ICommand Content { get { return new RelayCommand(execute, canexecute); } } 
        

        private bool canexecute(object parameter)
        {
            return true;
        }

        private void execute(object parameter)
        {
            string.Format("{0} jest OK", Person.FullName);
            MessageBox.Show("Witaj " + Person.FullName);
            
        }



        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;

            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

1

No, a gdzie masz konstruktor o którym napisał @Ktos ? Po utworzeniu obiektu Twój kod zadziała

public PersonViewModel()
{
     this.Person = new Person();
}
0

Fakt działa, wielkie dzięki...szkoleniowy błąd. MessageBox się pokazuje, jeszcze tylko coś z bindowaniem Labela i Textboxa

0

Zmień w widoku do kontrolek zbindowanych do Imie i Nazwisko na UpdateSourceTrigger=PropertyChanged (domyślnie jest ustawione na LostFocus i zmiany będą widoczne dopiero po utracie focus'a na kontrolce).

oraz:

private string _Imie;
        public string Imie
        {
            get { return _Imie; }
            set
            {
                _Imie = value;
                OnPropertyChanged("Imie");
                OnPropertyChanged("FullName");
            }
        }

        private string _Nazwisko;
        public string Nazwisko
        {
            get { return _Nazwisko; }
            set
            {
                _Nazwisko = value;
                OnPropertyChanged("Nazwisko");
                OnPropertyChanged("FullName");

            }
        }
0

Wszytko działa jak należy, dzięki wielkie.

1 użytkowników online, w tym zalogowanych: 0, gości: 1