Search code examples
wpfmvvmbindingwindow

WPF using one VIewModel to manipulate TextBoxes in two seperate windows


I am having a problem with binding data. I'd like to bind text of TextBox which is in MainWindow to another TextBox which is in ChildWindow. While being in MainWindow, user can input a string into that TextBox. ChildWindow will be only displaying some data. I've managed to bind the TextBox from MainWIndow and I can see that while debugging it hits MainWindowViewModel, However there's no effect on the ChildWindow.

My App.xaml.cs looks like this:

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        var window = new MainWindow() { DataContext = new MainWindowViewModel() };
        window.Show();

        base.OnStartup(e);
    }
}

then MainWIndow creates an instance of ChildWindow and they both use same ViewModel as below:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        var viewModel = new MainWindowViewModel();
        ChildWindow childWindow = new ChildWindow();
        childWindow.DataContext = viewModel;
        childWindow.Show();
        InitializeComponent();
        DataContext = viewModel;
    }
}

MainWindowViewModel:

public class MainWindowViewModel : ViewModelBase
{
    public string _firstTeamName { get; set; }
    public string FirstTeamName
    {
        get { return _firstTeamName; }
        set
        {
            _firstTeamName = value;
            OnPropertyChanged(nameof(FirstTeamName));
        }
    }
}

ViewModelBase:

public abstract class ViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        var handler = this.PropertyChanged;
        if (handler != null)
        {
            handler(this, e);
        }
    }
}

Binding in MainWindow.xaml:

<TextBox x:Name ="firstTeam"  Height="30" VerticalAlignment="Top" Text ="{Binding FirstTeamName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>

Binding in ChildWindow.xaml:

<TextBlock Text ="{Binding FirstTeamName}" FontSize="24"></TextBlock>

Solution

  • Your mistake is to set the MainWindow.DataContext twice.

    1. Inside the contructor of MainWindow
    2. In App.OnStartUp with var window = new MainWindow() { DataContext = new MainWindowViewModel() };

    What does happen here?

    • new MainWindow() will call the constructor and set the DataContext of MainWindow and ChildWindow to the same instance of MainWindowViewModel.
    • { DataContext = new MainWindowViewModel() } will overwrite the DataContext of MainWindow with a new instance of MainWindowViewModel.

    Now the two windows have two different instances of the ViewModel and will not work as expected.

    This should fix it

    public partial class App : Application
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            var window = new MainWindow() 
            { 
                // DataContext = new MainWindowViewModel() 
            };
            window.Show();
    
            base.OnStartup(e);
        }
    }