Monitoring other classes with one class - c#

I have one class named DataClass. This Class is responsible to saving information in database, and In this class there are some methods for saving and reading from database, Except this class I have other classes called HTMLEditor, QueryBuilder , EmailSending, InforDetails.
I need to listen to other classes by my data class , any time their information are changed then my Dataclass would be notified to save these information.
I know there is one design pattern is called observer design pattern , with this design pattern, other classes(observers) are listening to one class(subject),any time the status of subject is changed then other observers are notified.
What should I do for this problem? Is there any design pattern for this situation?

I think the interface you seek if INotifyPropertyChanged.
Microsoft Documentation: INotifyPropertyChanged
The implementation is very simple.
In every property set you do:
public bool MyProperty
{
get { return myField; }
set
{
if (myField != value)
{
myField= value;
NotifyPropertyChanged();
}
}
}
And the method and events:
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
Every observer only need to register to that event and they get a feedback when a property changed and which one did.
As extra, some control like PropertyGrid automatically register themselves when you feed them an object that implement that interface.

The INotifyPropertyChanged interface could be what you're after:
See here: http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx
You basically subscribe to an event within your other classes and those classes raise the event when a property changes.
Also, this SO question has an answer that is quite cool: Automatically INotifyPropertyChanged

Related

Should I have one ViewModel class implementing INotifyPropertyChanged for each Model class?

Basically, I have a model with various classes that load my data in different collections, including collections of collections (e.g. Cart has a collection of Bundle, which has collections of Product) . If my understanding of MVVM is correct, I would need to make one ViewModel class that implements INotifyPropertyChanged (directly or through inheritance from a base class) for each of my model classes. Though I must admit it seems to me that it implies a lot of duplicated code, just, having the ViewModel associate each property of the model class with a OnPropertyChanged call.
Just like is shown in this article for instance.
Am I getting this right ?
I'm currently trying to understand the basics of MVVM, so I try to fully implement it in my programs without any additional framework (MVVM Light and others).
You don't need a ViewModel-Class for each Model-Class you have. Your Model-Classes should implement the INotifyPropertyChanged-Interface.
You need ViewModels to interact with your Views. In the ViewModels you can have instances of your Model-Classes.
Btw.: To avoid writing the code for INotifyPropertyChanged every time in each ViewModel and Model i've created an abstract base class where everything is derived from. This class looks like:
public abstract class NotifyBase : INotifyPropertyChanged
{
private readonly Dictionary<string, object> mapping;
protected NotifyBase()
{
mapping = new Dictionary<string, object>();
}
protected void Set<T>(T value, [CallerMemberName] string propertyName = "")
{
mapping[propertyName] = value;
OnPropertyChanged(propertyName);
}
protected T Get<T>([CallerMemberName] string propertyName = "")
{
if(mapping.ContainsKey(propertyName))
return (T)mapping[propertyName];
return default(T);
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemeberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if(handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}

using of INotifyPropertyChanged

Can someone explain me why need to use implementation of INotifyPropertyChanged when using binding in wpf?
I can bind properties without implementation of this interface?
For example i have code
public class StudentData : INotifyPropertyChanged
{
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
string _firstName = null;
public string StudentFirstName
{
get
{
return _firstName;
}
set
{
_firstName = value;
OnPropertyChanged("StudentFirstName");
}
}
}
And binding in .xaml
<TextBox Text="{Binding Path=StudentFirstName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Grid.Row="1"
Grid.Column="2"
VerticalAlignment="Center" />
this code from .xaml.cs
StudentData _studentData = new StudentData { StudentFirstName = "John", StudentGradePointAverage = 3.5};
public MainWindow()
{
InitializeComponent();
this.DataContext = _studentData;
}
why we need to use INotifyPropertyChanged in this case?
It is not my code.
You need INotifyPropertyChanged if you want a wpf form to be automatically updated when a property changes through code. Also some controllers might want to know if edits have been made in order to enable/disable a save-button, for instance. You also might be displaying the same property on different views; in this case INotifyPropertyChanged helps to immediately update the other view when you edit a property.
If you think that your form behaves well without INotifyPropertyChanged, then you can drop it.
Note that binding works even without INotifyPropertyChanged. See: Why does the binding update without implementing INotifyPropertyChanged?
I would implement the properties like this. In some rare cases it can help to avoid endless circular updates. And it is more efficient by the way.
private string _firstName;
public string StudentFirstName
{
get { return _firstName; }
set
{
if (value != _firstName) {
_firstName = value;
OnPropertyChanged("StudentFirstName");
}
}
}
Starting with C#6.0 (VS 2015), you can implement OnPropertyChanged like this:
private void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
When you bind to a property of StudentData such as the StudentFirstName then the binding class tests to see if the StudentData instance provides the INotifyPropertyChanged interface. If so then it will hook into the PropertyChanged event. When the event fires and it fires because of the StudentFirstName property then it knows it needs to recover the source value again because it has changed. This is how the binding is able to monitor changes in the source and reflect them in the user interface.
If you do not provide the INotifyPropertyChanged interface then the binding has no idea when the source value changes. In which case the user interface will not update when the property is changed. You will only see the initial value that was defined when the binding was first used.
It does need to be implemented in order for binding to work but that doesn't mean you always have to do it yourself. There are other options like Castle Dynamic Proxy (which wraps your classes in a proxy and injects INPC into all virtual properties) and Fody (which adds it to the IL in a post-processing step). It's also possible to implement yourself while at the same time reducing code bloat, as demonstrated in my answer to this question.

How to implement Property Change Notification

In MVVM how should I implement INotifyPropertyChanged interface: in a ViewModel class or in a Model class? How to handle model's property changed event if INotifyPropertyChanged interface has been implemented in a ViewModel?
First, you always implement it in your View Model, because that interface is used by the framework to update the UI when you updated data in the view model.
You can implement it in the Model, but it is by no means required. If the Model is changing out from under you, you could, and likely should, easily raise your own (semantically clearer) events that the View Model listens to in order to update its data.
The actual implementation should look like this (MSDN):
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}

ObservableCollection along with a repository

I am having trouble with grasping the concept of a ObservableCollection inside MVVM. For start I would like to point out that I am doing this in a Windows 8/Metro App, not WPF or Silverlight.
According to microsoft documentation, this collection has the following usefulness:
"Represents a dynamic data collection that provides notifications when items get added, removed, or when the whole list is refreshed." From what I understand this helps you a lot when binding is involved. On the net I found a lot of simple examples, by creating a ObservableCollection on runtime and then working on it, but I didn't find out what is the proper way of using this collection with a repository.
Let' say I have the following repository interface that is an implementation for a ORM database backend, or a raw ADO.NET implementation
public interface IRepository<T>
{
ObservableCollection<T> GetAll();
void Create();
void Update();
void Delete();
T GetByKey(object key);
}
and a simple ViewModel that use the repository as a model
public class ViewModel
{
private ObservableCollection<Dummy> _obsListDummy;
private RelayCommand _addCommand,_deleteCommand,_updateCommand;
private IRepository<Dummy> _repositoryDummy;
public class ViewModel()
{
_repositoryDummy=Factory.GetRepository<Dummy>();
}
public ObservableCollection<Dummy> ObsListDummy
{
get
{
return _repositoryDummy.GetAll();
}
}
public RelayCommand AddCommand
{
get
{
if (_addCommand == null)
{
_addCommand = new RelayCommand(p => DoAdd();
//DoAdd method shows a popup for input dummy and then closes;
);
}
return _myCommand;
}
}
........
}
My view would be a simple XAML with a grid, also Dummy object has INotifyPropertyChanged implemented.
Right now with this implementation after adding or updating or deleting, the ObservableCollection isn't refreshing, I know I could have put IEnumerable instead, but I dont'see an elegant solution of how would make repository to sync with the ObservableCollection that is in the model, other than subscrbing to CollectionChanged and there you treat all the states, but to it seems that I would repeat myself along with the logic that I do in the repository. And to make matters even worse, let's say I would like to get some push notification from my repository, towards the ObservableCollection.
I hope I was understand about my problem.
Thanks in advance.
You should implement INotifyPropertyChanged on your ViewModel and your ObsListDummy property should inform the ViewModel about changes applied to the collection. So it should look like this:
public class ViewModel: INotifyPropertyChanged
{
// Declare the event
public event PropertyChangedEventHandler PropertyChanged;
// Create the OnPropertyChanged method to raise the event
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
private ObservableCollection<Dummy> _dummyCollection;
public ObservableCollection<Dummy> DummyCollection
{
get { return _dummyCollection; }
set
{
// Set the value and then inform the ViewModel about change with OnPropertyChanged
_dummyCollection = value;
OnPropertyChanged("DummyCollection");
}
}
}
This whole INotifyPropertyChanged interface and implementation includes some dirty work like declaring event and creating a helper method to raise the event so I would suggest you to use some libraries for that like MVVM Light.
You should use a member of type ObservableCollection to store your Dummy ViewModels. In your Initialize method you read the dummies from the repository, create Dummy ViewModels and put those in the ObservableCollection. Now your view will get updated, when you use Binding to ObsListDummy (and add / remove from that collection, also note that Binding only works with public properties).
Right now, you just have a new ObservableCollection on each read, no events involved, so your View will never know about a change.
Further your ViewModel shall implement INotifyPropertyChanged.

Bindable ReadOnly List

I have a Ticket class containing a collection of TicketLine objects. I want to bind this collection to a DataGridView but without letting anything but the Ticket class add and remove items from it.
So far I have used a BindingList and implementet INotifyPropertyChanged in TicketLine, but this exposes Add and Remove methods on the list itself.
How do I this collection to a DataGridView without exposing other Add/Remove methods than those in the Ticket class?
What I can think of is to implement IBindingList interface using decorator pattern by delegating all calls to wrapped read/write BindingList. The only exceptions are:
AllowEdit/Add/Remove members which return false.
Add/Remove methods which throw InvalidOperationException (or NotSupportedException)
That's how read-only aspect is assured.
Once you create this read-only wrapper, you pass it to DataGridView. Provided that it respects the contract (I assume it does :)) it should disallow modifying the underlying list.
Once I faced the same problem and the solution was too troublesome to implement. Mainly because of loss of generics and the amount of work it required. I hope it helps, though.
You could hide the list and only expose an IEnumerable property:
public class Ticket : INotifyPropertyChanged
{
private List<TicketLine> ticketLines;
public IEnumerable<TicketLine> TicketLines
{
get { return ticketLines.AsReadOnly(); }
}
public void Add(TicketLine ticketLine)
{
ticketLines.Add(ticketLine);
OnPropertyChanged("TicketLines");
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}

Categories

Resources