Reputation:
I'm trying to create a very simple data binding app for practice but I can't get it to work, I've looked at a lot of different solutions but none of them help and I can't figure out the problem.
MainWindow.xaml:
<Window.DataContext>
<local:ViewModel/>
</Window.DataContext>
<Grid>
<TextBlock Text="{Binding BindText, UpdateSourceTrigger=PropertyChanged}"/>
</Grid>
Window1.xaml:
<Window.DataContext>
<local:ViewModel/>
</Window.DataContext>
<Grid>
<TextBox Text="{Binding BindText, UpdateSourceTrigger=PropertyChanged}"/>
</Grid>
ViewModel:
using System.ComponentModel;
namespace bindtest
{
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string bindText = "Hello";
public string BindText
{
get { return bindText; }
set
{
bindText = value;
OnPropertyChanged("BindText");
}
}
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
The text displays correctly when it first loads but then won't update. The text in MainWindow is meant to update when the text in window1 changes. Any solutions? Thanks
Upvotes: 2
Views: 359
Reputation: 4016
Since you are creating your view model via:
<Window.DataContext>
<local:ViewModel/>
</Window.DataContext>
you have 2 distinct instances of the view models. You have to bind the same instance of your view models against the views.
How to bind the same instance against 2 views?
The simplest way in your case is, to create a singleton:
public class ViewModel : INotifyPropertyChanged
{
public ViewModel Instance {get; } = new ViewModel();
// ....
}
and bind to it:
<Window DataContext="{Binding Source={x:Static local:ViewModel.Instance}}" /* ... */>
Note that it is not the best way....
You should use PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
or
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName)
to ensure that the handler wasn't unsubscribed beween checking for null and invoking the event handler!
Upvotes: 1
Reputation: 634
As JanDotNet suggests, you need to use a single instance of the view model. So in your app level code for instance you would do something like:
public partial class App : Application
{
private void App_Startup(object sender, StartupEventArgs e)
{
try
{
ViewModel vm = new ViewModel();
MainWindow w = new MainWindow(vm);
Window1 w1 = new Window1(vm);
w.Show();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
And then your window constructors modified like so:
public partial class MainWindow : Window
{
pulic MainWindow(ViewModel vm)
{
InitializeComponent();
DataContext = vm;
}
}
Upvotes: 2