how to implement observable int in wpf ViewModel? - c#

In my mvvm ViewModel I have such field
public int Delta { get; private set; }
However when I update it like that:
Delta = newValue;
UI is not refreshed.
I was thinking that databinding will do that for me. For example I can declare collection as ObservableCollection and then databinding will work.
However there are no ObservableInt, how to say View that it need to be refreshed then?
Probably I should raise some event "notify property changed" or something?

You have two choices:
Implement the INotifyPropertyChanged interface on your class.
Inherit from DependencyObject and implement Delta as a DependencyProperty.
The simplest option is #1. You can implement the INotifyPropertyChanged interface on your class quite easily:
public class YourClass : INotifyPropertyChanged
{
private int _delta;
public int Delta
{
get { return _delta; }
set { _delta = value; PropertyChanged?.Invoke(nameof(Delta)); }
}
public event PropertyChangedEventHandler PropertyChanged;
}
You can read more about using and implementing dependency properties on MSDN.

While we're at it with improving the answer, some of the other new additions of c# 6.0 and 7.0 help make it ever more compact:
public class Prop<T> : INotifyPropertyChanged
{
private T _value;
public T Value
{
get => _value;
set { _value = value; NotifyPropertyChanged(nameof(Value)); }
}
public event PropertyChangedEventHandler PropertyChanged;
internal void NotifyPropertyChanged(string propertyName) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
This way, you aren't using any "embedded values" (i.e - the property's name) and are keeping the code refactor-safe.
And there's also no need for redundant code blocks due to c# 6.0 and 7.0's new Expression body features

Using #LBushKin's Answer, i modified it to
public class Prop<T> : INotifyPropertyChanged
{
private T _value;
public T Value
{
get { return _value; }
set { _value = value; NotifyPropertyChanged("Value"); }
}
public event PropertyChangedEventHandler PropertyChanged;
internal void NotifyPropertyChanged(String propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
and to set it up:
class MainWindow ...
// a bool with initial value of true
public static Prop<bool> optionBool { get; set; } = new Prop<bool>{ Value = true };
private void Window_Loaded(object sender, RoutedEventArgs e)
{
// connect UI to be able to use the Prop
DataContext = this;
}
and to use it:
<Grid ...
<CheckBox Content="Da Check" ... IsChecked="{Binding optionBool.Value}"/>
There is also a Collection and 2-Properties version here:
Utils.ObservableProperties.cs (this repo contains several related classes)

Just implement INotifyPropertyChanged Interface in your class and use it to raise a PropertyChanged for your Property and then UI will update. If you are using an MVVM project template then there is a good chance you already have a helper method implemented you only need to use it.
MSDN INotifyPropertyChanged
GalaSoft MVVM Light Toolkit

The ObservableCollection raises events automatically but for your own properties you have to raise the events yourself.
A good example is here: http://www.codeproject.com/Tips/228352/Naming-Properties-in-MVVM?display=Print
I'd suggest using mvvm light: http://mvvmlight.codeplex.com, I used it in silverlight and wpf applications. Very easy to use and provides a messageing system between model, view model and view.

Adding on to https://stackoverflow.com/a/8316100/5725669, there is a new and easy way to do this without remembering to keep track of PropertyChanged?.Invoke(nameof(Delta)); in every location
public class YourClass : INotifyPropertyChanged
{
private int _delta;
public int Delta
{
get { return _delta; }
set {
_delta = value;
// Call OnPropertyChanged whenever the property is updated
OnPropertyChanged();
}
}
// Declare the event
public event PropertyChangedEventHandler PropertyChanged;
public YourClass()
{
}
// Create the OnPropertyChanged method to raise the event
// The calling member's name will be used as the parameter.
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
It makes use of CallerMemberName for skipping manual entries for property name. More details on this MSDN Doc

Related

MVVM update view model when model changes

I need to update ViewModel, when Model changes and Model, when ViewModel changes. In my case, I have: ProjectViewModel implementing INotifyPropertyChanged and Project(model) implementing INotifyPropertyChanged. When ViewModel changes I simply change Model directly. But when Model changes, then what? I tried to handle Model's property changed event in ViewModel. But then I will have strong reference from long-live Model and that will cause memory leak, or not? If yes so how to do it otherwise?
EDIT:
class ProjectViewModel : INotifyPropertyChanged
{
private Project Project;
public string Name
{
get
{
return Project.Name;
}
set
{
Project.Name = value;
OnPropertyChanged("Name");
}
}
public ProjectViewModel(Project project)
{
this.Project = project;
project.PropertyChanged += OnProjectChanged;
}
private void OnProjectChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Name")
OnPropertyChanged("Name");
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
} //and then things for UI....
}
class Project : INotifyPropertyChanged
{
private string name;
public string Name
{
get
{
return name;
}
set
{
name = value;
OnPropertyChanged("Name");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}//and then logic (for saving)
}
EDIT2: Or can I implement something like IDisposable in ViewModel? Or make model(Project) property in ViewModel public and bind to it directly?
If your VM depends in any way on the value of a property in the model then yes, you will need to subscribe to its INPC notifications. But the reality is that usually the VM doesn't need to know about specific model values unless it is aggregating the values (i.e. summing a value from a list of objects).
When you do need to subscribe to the model's INPC then you'll also need to unsubscribe. This is not as troublesome as it might seem because the VM triggers the fetching or refetching of the models so it is clear when the unsubscribing needs to be done. Check the INotifyCollectionChanged interface - this is a good place to start for the subscribing and unsubscribing.
Personally, I would do what you suggested in your second edit, implementing INotifyPropertyChanged on the Model, making Project a public property, and binding to Project.Name directly.

notify viewmodel2 if viewmodel1 property changes

I have a scenario in wpf +mvvm i.e if my particular property changes in viewmodel1 then i wan to notify viewmodel2 having observable collection that property "A" has bee changed
1)I want to fire it for particular property not for all.
i have tried below code but not working .please let me know how cam i do this.
public class Model1 : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
// Create custom event
public event EventHandler NotifyChange;
private string testProperty;
public string TestProperty
{
get
{
return testProperty;
}
set
{
testProperty = value;
// If changing properties, fire your OnPropertyChanged to update UI
OnPropertyChanged("TestProperty");
}
}
private void OnPropertyChanged(string propName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
// Fire your custom event if a property changed
NotifyChange(this, null);
}
}
}
public class Model2 : INotifyCollectionChanged
{
public event NotifyCollectionChangedEventHandler CollectionChanged;
public Model2()
{
// Assuming there is an accessible instance of model1
Model1 m1Instance = new Model1();
// Hook up your NotifyChange event from model1
m1Instance.NotifyChange += Model1Changed;
}
private void Model1Changed(object sender, EventArgs e)
{
// this will be triggered on change in model1
}
private void OnCollectionChanged(object singleObject)
{
if (CollectionChanged != null)
CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset, singleObject));
}
}
Use PubSub Events
My suggestion would be to look into PubSub events.
My recommendation of doing this, is to use Prism. Here's some more information: http://www.c-sharpcorner.com/UploadFile/5ffb84/prism-event-aggregator-in-wpf-with-mvvm/
You will be sticking to proper MVVM practices in this case.
Here's MSDN's ever-useful guide: https://msdn.microsoft.com/en-us/library/ff649664.aspx
Have a really good read-up on how this works, and how to use/implement it.
Alternatively
This will work, but I would still defer to using PubSub events if possible.
You could try this:
public class Model1 : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _property;
public string Property
{
get { return _property; }
set
{
_property = value;
OnPropertyChanged("Property");
}
}
private void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class Model2
{
public Model2()
{
// You might be storing your Model1 as a property in the Model2?
// I don't know, but I've put it in the constructor just for example.
var model1 = new Model1();
model1.PropertyChanged += OnModel1PropertyChanged;
}
private void OnModel1PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Property")
{
// Do stuff here when the right property has changed in model 1
}
}
}
I have only new'd up a Model1 in the constructor of Model2 as an example - you might be assigning it and storing as a field or property elsewhere in the Model2 ViewModel.
This might be particularly useful if you have ViewModels within ViewModels (parent VM > child VMs).
I use parent > child VMs quite regularly, and I don't think it's against MVVM best practices, but I still use the EventAggregator, instead of events.
As a side note, if you are using C#6:
Use nameof(Property) instead of "magic strings" (e.g. "Property"). This makes for much easier refactoring and compiler can tell you about errors - but essentially does the same job. Use this in the OnPropertyChanged() call in your setter
You can also use the nameof keyword when checking the property name, with the same principle as above. Like this: if (e.PropertyName == nameof(Model1.Property)) ...
Use null propagation: PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));. Changes the method body of your OnPropertyChanged to a nice one-liner, whilst still doing the same job
I digress
I would always look at sticking to proper MVVM practices, where possible.
I use Prism's EventAggregator on a daily basis and will swear by it.
Have a good read up on PubSub Events (you can use any type of event aggregator, but I would say to use Prism's, preferably)
Hope this helps! :)
If this is just to notify Model2 I think you dont need all these implementations. You can do something like
public string TestProperty
{
get
{
return testProperty;
}
set
{
testProperty = value;
// If changing properties, fire your OnPropertyChanged to update UI
OnPropertyChanged("TestProperty");
//Here you can call a method of Model2 sating that its changed
Model2 m2Instance = new Model2();
m2Instance.ValueChanged();
}
}
Add the method ValueChanged in you model 2.
That's because you're not registering to PropertyChanged. You're registering your event handler on NotifyChange so that PropertyChanged in Model1 is NULL and so NotifyChange is not fired.
So, you need to implement your OnPropertyChanged as the following:
private void OnPropertyChanged(string propName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propName));
if (NotifyChange != null)
NotifyChange(this, null);
}
Finally, if you want your NotifyChange to be fired for a specific property, then adjust the code above to check for the propName before you fire the event.

How to update WPF binding from a helper class

I'm sure this is a very basic question but I don't even know the technical term / jargon to Google and self-educate on.
I have created a simple model implementing INotifyPropertyChanged.
public class PushNotes : INotifyPropertyChanged
{
public string CompletePushNotes { get; set; }
}
Binding in cs:
evt_pushNotes = new PushNotes()
{
CompletePushNotes = "HelloThere"
};
this.DataContext = evt_pushNotes;
//snip later in code
Helpers.UpdateCompletePushNotes();
In XAML:
<xctk:RichTextBox x:Name="PushEmail" Text="{Binding Path=CompletePushNotes, Mode=OneWay}" ScrollViewer.VerticalScrollBarVisibility="Auto" Margin="40,398,40,40">
<xctk:RichTextBox.TextFormatter>
<xctk:PlainTextFormatter />
</xctk:RichTextBox.TextFormatter>
</xctk:RichTextBox>
Helper:
internal static class Helpers
{
internal static void UpdateCompletePushNotes()
{
//duhhhh what do I do now??
//If I create a new PushNotes it will be a different instantiation....???
}
}
Now this is all fine but I have a method in a helper class that needs to change the CompletePushNotes.
Again I know this is a simplistic / newbie question but I don't know what I need to learn.
So do I make my PushNotes class static, or singleton. Is there some global binding "tree" I can walk to find my instantiated and bound PushNotes class that is attached to the UI element?
Not looking for an a handout just need to know what it is I'm looking for.
TIA
Your PushNotes class does not implement the INotifyPropertyChanged interface. Once you have implemented it, you need to modify your CompletePushNotes property to have a backing field and in the setter of the property you can raise the PropertyChanged event to notify the UI of the source property update.
public class PushNotes : INotifyPropertyChanged
{
string completePushNotes;
public string CompletePushNotes
{
get
{
return completePushNotes;
}
set
{
completePushNotes = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
Making the PushNotes class static will not help you. You seem to have a variable of some sort to the PushNotes instance (evt_pushNotes), so just do:
evt_pushNotes.CompletePushNotes = something;
If you have a helper class that does something, call the method in the helper class and get the value back or pass the PushNotes instance into the helper class as a parameter.
internal static class Helpers
{
internal static void UpdateCompletePushNotes(PushNotes pushNotes)
{
pushNotes.CompletePushNotes = something;
}
}

Is there an event that will raise when a variable has changed?

I know that the proper course of action is to create a class, make an event in said class, then use said class in another part of the program where the variable would be changed (e.g. Use said class in the equal button of a calculator, so that an event handler knows that a variable has been changed because an event would be fired). But, trying to streamline my code, I'm looking for a way to monitor a variable directly without an infinite loop/timer and raise an event when it changes. Is there such a thing? If not, are there any other alternatives aside for the one I mentioned?
Here is what I'm trying to mention:
Code that changes a variable -> Another piece of code (not a loop) watching for changes then throws an event if there are changes -> Event handler
You can't do it with fields but with properties:
class SomeClass : INotifyPropertyChanged
{
private string someProperty;
public string SomeProperty
{
get { return someProperty; }
set { someProperty = value; OnPropertyChanged(); }
}
private void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged = delegate {};
}
Edit (.net 4.0)
class SomeClass : INotifyPropertyChanged
{
private string someProperty;
public string SomeProperty
{
get { return someProperty; }
set { someProperty = value; OnPropertyChanged("SomeProperty"); }
}
private void OnPropertyChanged(string propertyName)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged = delegate {};
}
Edit (Winforms example)
public partial class Form1 : Form
{
private SomeClass theObject = new SomeClass(); //keep a reference of the object.
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
//here we do the binding... we want the 'Text' Property of the control to change if the 'SomeProperty' changes OnPropertyChanged
textBox1.DataBindings.Add("Text",theObject,"SomeProperty",false,DataSourceUpdateMode.OnPropertyChanged);
}
private void button1_Click(object sender, EventArgs e)
{
theObject.SomeProperty = "This works!"; //just a test button that changes the property...
}
}
Though I know that it is an often undesired practice here at Stack Overflow, you may find my project NMF Expressions interesting: http://nmfexpressions.codeplex.com/
Basically, the project aims to allow you to write such as follows:
var myObservedVariable = Observable.Expression(() => whatever you want)
In this scenario, myObservedVariable will be of INotifyValue<T> which provides a ValueChanged event. Alternatively, you can use the query syntax. Alternatively, you may have a look at other similar frameworks like Obtics, BindableLINQ or ContinuousLINQ. A comparison of the latter was done in Bindable Linq vs. Continuous Linq.
However, this only works under pretty strong assumptions like all the object models that you are working with completely support INotifyPropertyChanged and INotifyCollectionChanged.
In addition to #Florian's answer, you can inject an implementation of the INotifyPropertyChanged interface at compile time using Fody.PropertyChanged.

List<string> INotifyPropertyChanged event

I have a simple class with a string property and a List property and I have the INofityPropertyChanged event implemented, but when I do an .Add to the string List this event is not hit so my Converter to display in the ListView is not hit. I am guessing the property changed is not hit for an Add to the List....how can I implement this in a way to get that property changed event hit???
Do I need to use some other type of collection?!
Thanks for any help!
namespace SVNQuickOpen.Configuration
{
public class DatabaseRecord : INotifyPropertyChanged
{
public DatabaseRecord()
{
IncludeFolders = new List<string>();
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
protected void Notify(string propName)
{
if (this.PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
#endregion
private string _name;
public string Name
{
get { return _name; }
set
{
this._name = value;
Notify("Name");
}
}
private List<string> _includeFolders;
public List<string> IncludeFolders
{
get { return _includeFolders; }
set
{
this._includeFolders = value;
Notify("IncludeFolders");
}
}
}
}
You should use ObservableCollection<string> instead of List<string>, because unlike List, ObservableCollection will notify dependents when its contents are changed.
And in your case I'd make _includeFolders readonly - you can always work with one instance of the collection.
public class DatabaseRecord : INotifyPropertyChanged
{
private readonly ObservableCollection<string> _includeFolders;
public ObservableCollection<string> IncludeFolders
{
get { return _includeFolders; }
}
public DatabaseRecord()
{
_includeFolders = new ObservableCollection<string>();
_includeFolders.CollectionChanged += IncludeFolders_CollectionChanged;
}
private void IncludeFolders_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
Notify("IncludeFolders");
}
...
}
The easiest way to make WPF's list binding work is to use a collection that implements INotifyCollectionChanged. A simple thing to do here is to replace or adapt your list with an ObservableCollection.
If you use ObservableCollection, then whenever you modify the list, it will raise the CollectionChanged event - an event that will tell the WPF binding to update. Note that if you swap out the actual collection object, you will want to raise the propertychanged event for the actual collection property.
Your List is not going to fire the NotifyPropertyChanged event automatically for you.
WPF controls that expose an ItemsSource property are designed to be bound to an ObservableCollection<T>, which will update automatically when items are added or removed.
You should have a look at ObservableCollection

Categories