Changing viewmodel - c#

I have simplified app to show my issue
When I click button, it changes Text property of ViewModel and TextBlock.Text is updated.
MainPage.xaml
<StackPanel>
<Button Click="ButtonBase_OnClick">Button to change text</Button>
<TextBlock Text="{x:Bind ViewModel.Text, Mode=OneWay}"></TextBlock>
</StackPanel>
MainPage.xaml.cs
public MainPage()
{
ViewModel = new ViewModel();
this.InitializeComponent();
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
ViewModel.Text = "x:Bind works";
}
ViewModel class has one string property (Text) and implemented INotifyPropertyChange interface.
Problem starts when ViewModel is not set in ctor (i.e. viewModel is null and changed in runtime):
public MainPage()
{
//ViewModel = new ViewModel();//this line has been removed
this.InitializeComponent();
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
ViewModel = new ViewModel();//this line has been added
ViewModel.Text = "x:Bind does not work";
}
Complited binding is not working (Text is not changed) and I could not figure out why it is so... I need to change viewModel from null (vm is null because it is waiting for some data in real app)

{x:Bind} bindings (often referred-to as compiled bindings) uses generated code to achieve its benefits. At XAML load time, {x:Bind} is converted into what you can think of as a binding object, and this object gets a value from a property on a data source. These generated code can be found in your obj folder, with names like (for C#) <view name>.g.cs.
For your code, the generated code will like following:
// Update methods for each path node used in binding steps.
private void Update_(global::UWP.BlankPage3 obj, int phase)
{
if (obj != null)
{
if ((phase & (NOT_PHASED | DATA_CHANGED | (1 << 0))) != 0)
{
this.Update_ViewModel(obj.ViewModel, phase);
}
}
}
private void Update_ViewModel(global::UWP.ViewModel obj, int phase)
{
this.bindingsTracking.UpdateChildListeners_ViewModel(obj);
if (obj != null)
{
if ((phase & (NOT_PHASED | DATA_CHANGED | (1 << 0))) != 0)
{
this.Update_ViewModel_Text(obj.Text, phase);
}
}
}
...
private global::UWP.ViewModel cache_ViewModel = null;
public void UpdateChildListeners_ViewModel(global::UWP.ViewModel obj)
{
if (obj != cache_ViewModel)
{
if (cache_ViewModel != null)
{
((global::System.ComponentModel.INotifyPropertyChanged)cache_ViewModel).PropertyChanged -= PropertyChanged_ViewModel;
cache_ViewModel = null;
}
if (obj != null)
{
cache_ViewModel = obj;
((global::System.ComponentModel.INotifyPropertyChanged)obj).PropertyChanged += PropertyChanged_ViewModel;
}
}
}
Here I just copy some method that related to your issue. From these method, you can find that before update TextBlock or PropertyChanged listeners, it will check if the ViewModel is null. If it is null, nothing will be done. So to make {x:Bind} work, we must initialize ViewModel before page loaded. And this is the reason why {x:Bind} doesn't work when you initialize ViewModel in Button.Click event.
To fix this issue, you can implement INotifyPropertyChanged interface for ViewModel like Filip said so that the generated code can be notified when ViewModel changed (from null to new ViewModel()) and update you UI.
But I think you can just initialize ViewModel in constructor. When you initialize ViewModel, you can set the properties that you are waiting for to null first like:
public MainPage()
{
ViewModel = new ViewModel() { Text = null };
this.InitializeComponent();
}
And then update these properties when your date is ready. In this way, you can do not implement INotifyPropertyChanged interface on your page.
Besides these, there is another cheaper way, you can call this.Bindings.Update(); method to force the bindings to be updated after you initialize ViewModel like following:
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
ViewModel = new ViewModel();
ViewModel.Text = "x:Bind does not work";
this.Bindings.Update();
}

Did you implement INotifyPropertyChanged on page like so
public sealed partial class MainPage : Page, INotifyPropertyChanged
{
private ViewModel viewModel;
public ViewModel ViewModel
{
get { return viewModel; }
set
{
viewModel = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ViewModel)));
}
}
public MainPage()
{
ViewModel = new ViewModel { };
this.InitializeComponent();
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
ViewModel = new ViewModel { };//this line has been added
ViewModel.Text = "x:Bind does not work";
}
public event PropertyChangedEventHandler PropertyChanged;
}
This works for me.

Related

Can't add item to Observable Collection (or UI is not being refreshed)

I have a noob problem. As the title says, I'm having a problem with an observable collection.
I'm trying to fill a collection passing a value trough a TextBox, and then adding it to an observable collection. When I press the button "Add Ciudad", a TextBox to insert the new value and a button to save it is displayed.
The value gets successfully to the method in charge of doing that ("Add Input City"), but the UI never shows the new item.
By the way, the first value added manually in "Load Ciudades" shows properly.
I saw some related questions, but still I'm not able to solve the problem.
I suspect I'm not properly adding the items. For more trouble, I'm a completely noob with C# :D.
Here's the code so you can judge:
Cities model:
public class Ciudad : INotifyPropertyChanged
{
private string nombre;
public String Nombre
{
get { return nombre; }
set {
nombre = value;
RaisePropertyChanged("Nombre");
RaisePropertyChanged("Ciudades"); //Dunno if this one is necesary.
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
Cities view model:
public ObservableCollection<Ciudad> Ciudades { get; } = new ObservableCollection<Ciudad>();
public void LoadCiudades()
{
Ciudades.Add(new Ciudad { Nombre = "Random city" });
}
public void AddInputCity(string new_city)
{
Ciudades.Add(new Ciudad { Nombre = new_city });
}
Cities view:
<Grid>
<DataGrid ItemsSource = "{ Binding Path = Ciudades, UpdateSourceTrigger=PropertyChanged }" Name="DGrid">
</DataGrid>
<Button Click="Button_Click" Height="30" Width="150" Margin="0,250,0,0">Add Ciudad</Button></Grid>
Cities view cs
TextBox iTextBox;
public CiudadesView()
{
InitializeComponent();
}
private void Add_Input_Text()
{
TextBox iText = new TextBox
{
Name = "iText",
Width = 250,
Margin = new Thickness(100)
};
Button saveBtn = new Button()
{
Content = "Save"
};
saveBtn.Click += new RoutedEventHandler(Button_Save_Click);
sPanel.Children.Add(iText);
sPanel.Children.Add(saveBtn);
iTextBox = iText;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Add_Input_Text();
}
private void Button_Save_Click(object sender, RoutedEventArgs e)
{
string ciudadNuevoNombre = iTextBox.Text;
CiudadesViewModel viewModel = new CiudadesViewModel();
viewModel.AddInputCity(ciudadNuevoNombre);
}
Any ideas or suggestions?
Thank you all! : )
Make sure that you call the AddInputCity method of the existing view model instance in your Button_Click event handler, e.g.:
private void Button_Click(object sender, RoutedEventArgs e)
{
var viewModel = DataContext as YourViewModelClass;
if (viewModel != null)
viewModel.AddInputCity("new...");
}
You've not shown us your click code and several other things like the relationship between view and viewmodel.
I suggest you also take a look at binding commands rather than click handlers.
This is an article intended to introduce the reader to MVVM which adds an item to a bound observablecollection using a command:
https://social.technet.microsoft.com/wiki/contents/articles/32164.wpf-mvvm-step-by-step-2.aspx

Binding label to a variable

I am just starting with WPF and I am trying to setup binding between a local variable and a label. Basicaly I want to update the label when local variable changes. I was searching for solution but they all just use textbox as a source not just class variable and I am not even sure it works this way. So here is my code.
public partial class MainWindow : Window
{
int idCounter;
public MainWindow()
{
InitializeComponent();
Binding b = new Binding();
b.Source = idCounter;
b.Mode = BindingMode.OneWay;
b.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
myLabel.SetBinding(Label.ContentProperty,b);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
idCounter++;
}
}
Button does work, idCounter changes value, but it does not update in label so I guess binding is wrong. Can someone tell me what is wrong? Thanks
Your code will work if you change your class to this...
public partial class Window1 : Window, INotifyPropertyChanged
{
private int _idCounter;
public int IdCounter
{
get { return _idCounter; }
set
{
if (value != _idCounter)
{
_idCounter = value;
OnPropertyChanged("IdCounter");
}
}
}
public Window1()
{
InitializeComponent();
myLabel.SetBinding(ContentProperty, new Binding("IdCounter"));
DataContext = this;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
e.Handled = true;
IdCounter++;
}
#region INotifyPropertyChanged Implementation
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string name)
{
var handler = System.Threading.Interlocked.CompareExchange(ref PropertyChanged, null, null);
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
#endregion
}
Some of the issues you were having are...
The window itself should implement INotifyPropertyChanged so that the binding engine can place an ear on it.
the IdCounter needs to be public and have a public getter on it so that the binding engine can 'get' it.
You should set the DataContext to whatever class has declared IdCounter (the MainWindow in this case). Part of the problem was that the binding engine had no DataContext.
The BindingMode setting was a red-herring since a Label binds that way by default.
The UpdateSourceTrigger was a red-herring since the content of the label does not have a mechanism to update the source property. A label's content is not like a text box where the user can type something that the code needs to know about. When you're binding to something that the user cannot change, forget about UpdateSourceTrigger, it's the Target property that counts.
The handler should mark the event. This is good practice and did not affect the binding.
The binding constructor needs only the path.
This code will give you your expected result; i.e., that the label updates when the button is clicked. Checked, compiled, and executed on vs2013, .net 4.5.
The other respondents said you should use a View Model. I agree with this 100%, and overall it's a good thing to consider.
You want to use a property to do this, as well as implementing INotifyPropertyChanged so that the label's content gets updated when the property changes.
Here's an example using a simple ViewModel
xaml:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:converters="clr-namespace:WpfApplication1"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<Label Width="200" Height="50" Content="{Binding MyLabel}"/>
<Button Height="30" Width="100" Content="Increment" Click="Button_Click" />
</StackPanel>
</Window>
xaml.cs:
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
MainViewModel vm = new MainViewModel();
public MainWindow()
{
InitializeComponent();
this.DataContext = vm;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
vm.MyLabel += 1;
}
}
}
MainViewModel.cs:
namespace WpfApplication1
{
public class MainViewModel : INotifyPropertyChanged
{
#region Members
private int _myLabel;
#endregion Members
#region Properties
public int MyLabel
{
get
{
return _myLabel;
}
set
{
_myLabel = value;
NotifyPropertyChanged("MyLabel");
}
}
#endregion Properties
public MainViewModel()
{
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
}
Note: Ideally, you would want to use a Command for the Button instead of a Click event handler
You cannot bind to something that is private or a field so convert it into public property. You can find more as to what is a valid binding source here
If you want changes to your property be picked up by UI you should implement INotifyPropertyChanged interface and raise event each time value of the property changes. So idCounter should look more like this:
private int _idCounter;
public int idCounter
{
get { return _idCounter; }
set
{
if (_idCounter != value)
{
_idCounter = value;
OnPropertyChanged("idCounter");
}
}
}
When you create binding to property you use Path
Binding works in binding context so you need to specify from where to take this Path. Easiest way to do that is to set DataContext. So in your case initialization should look more like this:
Binding b = new Binding("idCounter");
b.Mode = BindingMode.OneWay;
b.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
myLabel.SetBinding(Label.ContentProperty, b);
DataContext = this;
As #d.moncada suggested in his answer you should create dedicated view model

WPF Combobox "leaks" memory

I have run into an issue with combo boxes in WPF where they seem to hang onto the first DataContext they were opened with. When I change the DataContext on my ComboBox, a child PopupRoot object still references the old DataContext.
At first I assumed we were doing something wrong but I was having trouble working out what that might be so I tried to simplify. I have managed to recreate the behavior I am seeing in our application in a very simple form so it seems more like a bug in the WPF ComboBox implementation. That sounds a little controversial so I thought I'd turn to stackoverflow for help.
The core code for the sample is below:
<Window x:Class="ComboBoxTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="150" Width="525">
<DockPanel>
<Button Click="ReloadModel" Width="137" Height="40">Reload Model</Button>
<ComboBox Name="ComboBox"
ItemsSource="{Binding AvailableOptions}"
SelectedItem="{Binding SelectedOption}"
Width="235" Height="43">
</ComboBox>
</DockPanel>
</Window>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var newModel = new ViewModel();
ComboBox.DataContext = newModel;
}
private void ReloadModel(object sender, RoutedEventArgs e)
{
var newModel = new ViewModel();
ComboBox.DataContext = newModel;
}
}
public class ViewModel : INotifyPropertyChanged
{
public ViewModel()
: this(new[] { "Option 1", "Option 2", "Option 3" })
{ }
public ViewModel(IEnumerable<string> options)
{
_selectedOption = options.First();
_availableOptions = new ObservableCollection<string>(options);
}
protected void RaisePropertyChanged(string propertyName)
{
var propertyChangedHandler = PropertyChanged;
if (propertyChangedHandler != null)
{
propertyChangedHandler(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
private readonly ObservableCollection<string> _availableOptions;
public ObservableCollection<string> AvailableOptions
{
get
{
return _availableOptions;
}
}
private string _selectedOption;
public string SelectedOption
{
get { return _selectedOption; }
set
{
if (_selectedOption == value)
{
return;
}
_selectedOption = value;
RaisePropertyChanged("SelectedOption");
}
}
}
Steps to reproduce:
1) Run Application
2) Open Combobox (so that it renders the drop down options)
3) Click "Reload Model" button
At this point there will be be two ViewModel objects, the older, unexpected instance is rooted like:
ViewModel->PopupRoot->Popup->ComboBox->MainWindow->App
Is this a bug or am I doing it wrong?
Eamon
Joe's comment brought my attention back to this old question which I have solved for my own use. In the end I wrote a Behavior that I could attach to a combobox that dealt with the memory leak.
I've posted the code here: https://github.com/EamonHetherton/Demos/blob/master/StackOverflow/18096050/StopComboBoxMemoryLeakBehaviour.cs
caveat emptor: this solution relies on reflection and the fragility that could entail. It works for me, YMMV.
Recently I encountered several memory leak problems which were related to Popup / ContextMenu / ComboBox binding with DataContext.
I found out that essentially the problem for Popup / ComboBox was that the "_popupRoot"'s DataContext was not released after the DataContext of its parents were set to null.
For ContextMenu, if it's used with some kind of ItemsSource binding generated controls, then WPF will cache the Contextmenu, so its DataContext will not be released unless the user right click to pop up the ContextMenu somewhere again.
I managed to create 3 derived classes to replace the WPF controls where DataContext binding was used. I will paste them here, hopefully, they may be useful to someone else.
public class ComboBoxFixMem : ComboBox
{
public ComboBoxFixMem()
{
this.DataContextChanged += ComboBox_DataContextChanged;
}
private void ComboBox_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (this.DataContext != null)
return;
FrameworkElement fe = this.GetTemplateChild("PART_Popup") as FrameworkElement;
if (null != fe)
fe.DataContext = null;
PopupFixMem.ClearPopupDataContext(fe as Popup);
}
}
public class ContextMenuFixMem : ContextMenu
{
protected override void OnClosed(RoutedEventArgs e)
{
base.OnClosed(e);
FrameworkElement p = this.Parent as FrameworkElement;
if (null != p)
p.DataContext = null;
}
}
public class PopupFixMem : Popup
{
public PopupFixMem()
{
this.DataContextChanged += Popup_DataContextChanged;
}
private void Popup_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (this.DataContext != null)
return;
ClearPopupDataContext(this);
}
public static void ClearPopupDataContext(Popup popup)
{
if (null == popup)
return;
try
{
var fiPopupRoot = typeof(Popup).GetField("_popupRoot", BindingFlags.NonPublic | BindingFlags.Instance);
var popupRootWrapper = fiPopupRoot?.GetValue(popup);
if (null == popupRootWrapper)
return;
var valueFieldInfo = popupRootWrapper.GetType().GetProperty("Value", BindingFlags.NonPublic | BindingFlags.Instance);
var popupRoot = valueFieldInfo?.GetValue(popupRootWrapper, new object[0]) as FrameworkElement;
if (null != popupRoot)
popupRoot.DataContext = null;
}
catch (Exception) { }
}
}

Silverlight with MVVM : How to access Event of the ViewModel from the View?

I have a MVVM application and somewhere in the application our company use a Third-Party that cannot use {Binding}. It's a component that draw shapes, etc. What I want it, when the ViewModel load from the persisted storage all shapes to notify the View to draw them. In a perfect world I would just have the take the Third-party and bind it to the ViewModel Shapes collection but I cannot.
From there, my idea was that I could get from the View the ViewModel (via the DataContext) and to hook the PropertyChanged event. The problem is that the DataContext is not yet initialized in the constructor, so it's NULL, and I cannot hook the event. Here is a sample of the code:
public CanvasView()
{
InitializeComponent();
((CanvasViewModel)this.DataContext).PropertyChanged += new PropertyChangedEventHandler(CanvasView_PropertyChanged); //Exception Throw here because DataContext is null
}
void CanvasView_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Shapes")
{
DrawShapes();
}
}
How can I get information from my ViewModel to my View in that case?
All of the answers so far breaks the MVVM pattern with having code-behind on the view. Personally I would wrap the 3rd party control in a UserControl and then wire up a few dependency properties with property change events.
C#
public partial class MyWrappedControl : UserControl
{
public static readonly DependencyProperty ShapesProperty = DependencyProperty.Register("Shapes", typeof(ObservableCollection<IShape>), typeof(MyWrappedControl),
new PropertyMetadata(null, MyWrappedControl.OnShapesPropertyChanged);
public ObservableCollection<IShape> Shapes
{
get { return (ObservableCollection<IShape>)GetValue(ShapesProperty); }
set { SetValue(ShapesProperty, value); }
}
private static void OnShapesPropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
((MyWrappedControl)o).OnShapesPropertyChanged(e);
}
private void OnShapesPropertyChanged(DependencyPropertyChangedEventArgs e)
{
// Do stuff, e.g. shapeDrawer.DrawShapes();
}
}
XAML
<UserControl
Name="MyWrappedControl"
x:Class="MyWrappedControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<!-- your control -->
<shapeDrawerControl x:Name="shapeDrawer" />
</UserControl>
you could also attach your handler in the Loaded event.
public CanvasView()
{
InitializeComponent();
this.Loaded += this.ViewLoaded;
}
void ViewLoaded(object sender, PropertyChangedEventArgs e)
{
((CanvasViewModel)this.DataContext).PropertyChanged += new PropertyChangedEventHandler(CanvasView_PropertyChanged);
}
void CanvasView_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Shapes")
{
DrawShapes();
}
}
I want to comment Dennis Roche answer.
Really, in this case we can use wrap approach, because we need to redraw view when Shapes collection changed. But view model logic can be too complex, and ,for instance, instead of redraw on PropertyChanged we should redraw on some custom event (f.i. ModelReloadEvent). In this case, wrapping doesn't help, but subscription on this event does, as in Muad'Dib solution - view model use event based communication with view, but this event should be view specific.
Using code-behind with View specific logic doesn't break MVVM. Yes, this code can be decorated with behavior/action, but using code behind - just simple solution.
Also, take a look at this view on MVVM. According to structure, ViewModel knows about abstract IView.If you worked with Caliburn/Caliburn.Micro MVVM frameworks you remember ViewAware class and IViewAware, which allows get view in view model.
So, more flexible solution I guess is next:
View:
public class CanvasView() : ICanvasView
{
public CanvasView()
{
InitializeComponent();
}
public void DrawShapes()
{
// implementation
}
}
ICanvasView:
public interface ICanvasView
{
void DrawShapes();
}
CanvasViewModel:
public class CanvasViewModel : ViewAware
{
private ObservableCollection<IShape> _shapes;
public ObservableCollection<IShape> Shapes
{
get
{
return _shapes;
}
set
{
_shapes = value;
NotifyOfPropertyChange(() => Shapes);
RedrawView();
}
}
private void RedrawView()
{
ICanvasView abstractView = (ICanvasView)GetView();
abstractView.DrawShapes();
}
}
Use the DataContextChanged event on the View (Window or UserControl)
public CanvasView()
{
InitializeComponent();
Action wireDataContext += new Action ( () => {
if (DataContext!=null)
((CanvasViewModel)this.DataContext).PropertyChanged += new PropertyChangedEventHandler(CanvasView_PropertyChanged);
});
this.DataContextChanged += (_,__) => wireDataContext();
wireDataContext();
}
void CanvasView_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Shapes")
{
DrawShapes();
}
}
update: Here is a documented way to get DataContextChanged in Silverlight 3 and 4 http://www.lhotka.net/weblog/AddingDataContextChangedInSilverlight.aspx

INotifyPropertyChanged implementation, binding does not work

I'm learning to create an app for WP7 (Mango), and somehow having this problem.
This is not actual code to my app, but a simplified version of the same problem. I think mostly it's due to lack of deep understanding of how binding works.
XAML.
<TextBlock x:Name="PageTitle" Text="{Binding Title}" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
Code Behind.
private MainPageViewModel viewModel;
// Constructor
public MainPage()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(MainPage_Loaded);
}
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
viewModel = new MainPageViewModel();
this.DataContext = viewModel;
}
private void ApplicationBarIconButton_Click(object sender, EventArgs e)
{
viewModel.GenerateTitle();
}
And my ViewModel.
private static int counter = 0;
private string title;
public string Title
{
get { return title; }
set
{
if (title != value)
{
title = value;
OnPropertyChanged("Title");
}
}
}
public MainPageViewModel()
{
title = "Init";
}
public void GenerateTitle()
{
if (counter == 0)
title = "0"; // Title = "0" will work fine.
if (counter == 1)
title = "1";
counter++;
}
Problem is, it only update the binding once inside my ViewModel constructor, so the title is "Init".
Any call to the GenerateTitle does not update the property. It works if I use 'Title' instead of 'title', which calls the setter.
Or I should really use 'Title'? I haven't done much C#, so my understanding of OOP is not that great yet.
The following line in the setter is what notifies the observers that he value has changed:
OnPropertyChanged("Title");
When you use the private field value, that method isn't being called so the observers aren't being notified that the value of the property has changed.
Because of that, you need to use the Property if you want the observers to be notified. You could also add the OnPropertyChanged("Title"); line to your GenerateTitle() method, but I would recommend just using the Property.
Yes you have to use Title as title just sets the field whereas Title runs the setter which raises the event

Categories

Resources