Problem with ObservableCollection and INotifyPropertyChanged in MVVM - c#

I have a chart control in XAML, and datapoints that are bind to the control.
The problem is when my ModelView changes the Collection of points the Chart control doesn’t get any notifications. I have tried dp, with ObservableCollection and INotifyPropertyChanged without any luck. I know that there is a difference between changing a field/property and making collection operations such as (add/remove/replace etc.) for the changes to propagate to the Chart control. But I haven’t got it to work. The change event is only triggered when I instance/reinstance the collection.
Does any have link to a working MVVM that works with collections?
Worth too know.
public class ObservableCollection : Collection, INotifyCollectionChanged, INotifyPropertyChanged
public static DependencyProperty WorkModelsProperty = DependencyProperty.Register("WorkModels", typeof(ObservableCollection), typeof(Chart),
new PropertyMetadata(new ObservableCollection { }, new PropertyChangedCallback(
(sender, args) =>
{
Debugger.Break(); //trigged only when collection got new instance
})));
public ObservableCollection WorkModels
{
get { return (ObservableCollection)GetValue(WorkModelsProperty); }
set { SetValue(WorkModelsProperty, value); }
}
The binding is correct and tested.
Code in Window.Resources.
ObjectDataProvider ObjectType="{x:Type vm:ListWorkViewModel}" x:Key="ListWorkViewModel"
The binding of control.
WorkModels="{Binding Source={StaticResource ListWorkViewModel}, Path=WorkModels}"
In the ViewModel I use the following code to rise changes. (When using INotifyPropertyChanged)
WorkModels.Add(workModel);
this.RaisePropertyChanged("WorkModels");
protected void RaisePropertyChanged(string propertyName)
{
VerifyPropertyName(propertyName);
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
When I use ObservableCollection I only add new data point to the collection.
WorkModels.Add(workModel);
Question on MVVM pattern on WPF?

Needs more code. How do you bind? What type is ObservableCollection of? Are you sure you are notyfing in class that is value of ObservableColletion?
Edit: Also change title of your question. This is little ambiguous and not really problem of your question.

You've got this:
WorkModels="{Binding Source={StaticResource ListWorkViewModel}, Path=WorkModels}"
Why are you binding to a static resource? how is that resource defined? Is it in the XAML itself? Are you sure you're actually updating the same instance of the model that the control is bound to?

Have you tried something like this...
private IEnumerable<DataPoint> _DataPoints;
public IEnumerable<DataPoint> DataPoints
{
get
{
return _DataPoints;
}
set
{
if (_DataPoints != value)
{
_DataPoints = value;
this.OnPropertyChanged("DataPoints");
}
}
}
Then whenever you modify ANY point within the DataPoints collection, you raise a property change event for the entire DataPoints set
/// <summary>
/// Raised when a property on this object has a new value.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Raises this object's PropertyChanged event.
/// </summary>
/// <param name="propertyName">The property that has a new value.</param>
protected virtual void OnPropertyChanged(string propertyName)
{
//this.VerifyPropertyName(propertyName);
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
var e = new PropertyChangedEventArgs(propertyName);
handler(this, e);
}
}
EDIT:
Try changing the resource type from StaticResource to DynamicResource...
http://msdn.microsoft.com/en-us/library/ms750613.aspx#staticdynamic
The resource could be being loaded with the page/window and never updated. That would explain the lack of event communication

Thank you for answers. I found the solution to the problem here.
http://msdn.microsoft.com/en-us/library/aa970563.aspx
For a dependency property in general, the implementation pattern that you follow is that you define a CLR property wrapper, where that property is backed by a DependencyProperty identifier rather than a field or other construct. You follow this same pattern when you implement a collection-type property. However, a collection-type property introduces some complexity to the pattern whenever the type that is contained within the collection is itself a DependencyObject or Freezable derived class.

Related

C# WPF Databinding an Image control to an array element [duplicate]

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.

XAML MVVM binding appears to have succeeded yet is bound to some other variable [duplicate]

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.

MvvmCross custom binding via INotifyPropertyChanged

I've got similar situation to this, but in Touch. Trying to deal with that via INotifyPropertyChanged though.
My code is the following:
set.Bind(txtSearch).For(x => x.Text).To(x => x.SearchText);
where txtSearch is my custom wrapper of UISearchBar. So, I can not inherit from MvxNotifyPropertyChanged as I already inherit from UIView (the wrapper is view).
Text property is:
public string Text { get
{
return _search.Text;
} set
{
_search.Text = value;
RaisePropertyChanged(() => Text);
}
}
and I fire it on the SearchBar text changing (which works).
I've also added the following:
public event PropertyChangedEventHandler PropertyChanged;
protected IMvxMainThreadDispatcher Dispatcher
{
get { return MvxMainThreadDispatcher.Instance; }
}
protected void InvokeOnMainThread(Action action)
{
if (Dispatcher != null)
Dispatcher.RequestMainThreadAction(action);
}
protected void RaisePropertyChanged<T>(Expression<Func<T>> property)
{
var name = this.GetPropertyNameFromExpression(property);
RaisePropertyChanged(name);
}
protected void RaisePropertyChanged(string whichProperty)
{
var changedArgs = new PropertyChangedEventArgs(whichProperty);
RaisePropertyChanged(changedArgs);
}
protected void RaisePropertyChanged(PropertyChangedEventArgs changedArgs)
{
// check for subscription before going multithreaded
if (PropertyChanged == null)
return;
InvokeOnMainThread(
() =>
{
var handler = PropertyChanged;
if (handler != null)
handler(this, changedArgs);
});
}
But when everything gets to RaisePropertyChanged, then I see that PropertyChanged is empty (so, seems no code is subscribed for my object). Which, of course, makes no notifications further.
I have similar situation but with some object inherited directly from MvxNotifyPropertyChanged, which seems working fine. Does that mean, that MvvmCross only can deal with such objects but not ones which generally use INotifyPropertyChanged?
Thank you!
INotifyPropertyChanged is used on the ViewModel side for property changes.
On the View side, MvvmCross uses DependencyProperty bindings on Windows, and C# methods, properties and events on the Xamarin platforms.
INotifyPropertyChanged isn't provided by default on the View side - since no off-the-shelf View objects support INotifyPropertyChanged, then there was no point in trying to bind to it within any of the MvvmCross View platforms.
However, the binding system is extensible - so if anyone wants to write INotifyPropertyChanged based views and wants to include a custom INotifyPropertyChanged binding for the View side, then they can do that following the steps similar to In MvvmCross how do I do custom bind properties and following examples linked from https://speakerdeck.com/cirrious/custom-bindings-in-mvvmcross
If they want to write an INotifyPropertyChanged-based system for the View side, then I'm sure this could be achieved using a custom binding approach - but it's not something I've personally done. I would expect such a custom binding to work both for INotifyPropertyChanged and for MvxNotifyPropertyChanged too (since MvxNotifyPropertyChanged implements INotifyPropertyChanged) - but I guess it would be up to the author to decide on the mechanics of that.

Simple-bound .NET data binding not working

Technology: .NET 4, C#, WinForms, Visual Studio 2010
I am in the processing of learning data binding and have been unable to get even a simple example to work as expected. I have a form with a label that I am binding to that shows the current mouse cursor coordinates.
public partial class Form1 : Form, INotifyPropertyChanged
{
[Bindable(true)]
private String cursorPosition;
public String CursorPosition
{
get
{
return cursorPosition;
}
set
{
cursorPosition = value;
NotifyPropertyChanged("CursorPosition");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public Form1()
{
InitializeComponent();
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
CursorPosition = "(" + Convert.ToString(e.X) + " , " + Convert.ToString(e.Y) + ")";
}
private void NotifyPropertyChanged(String propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
From the designer, I have set the label's Data Binding to bind the Text property to form1BindingSource - CursorPosition. What am I missing?
Edit: Updated code snippet.
From the designer, I have set the label's Data Binding to bind the Text property to form1BindingSource - CursorPosition. What am I missing?
Have you set:
form1BindingSource.DataSource = this; // (or whatever the real data source is)
e.g. in the form's constructor, after InitializeComponent?
(This assumes that your Form1 instance is the data source, and you're binding the controls to it via a BindingSource.)
A few further detail suggestions:
Choosing the form itself as data source is somewhat unusual. IMHO it's better to separate all bound-to properties into a separate, non-UI data object. This then allows you to create a reusable base type for the INotifyPropertyChanged implementation.
As #rfmodulator says in his answer, the BindableAttribute is attached to the field:
[Bindable(true)]
private String cursorPosition;
public String CursorPosition
…
You probably meant to attach it to the property:
private String cursorPosition;
[Bindable(true)]
public String CursorPosition
…
Your setter should probably look like this:
set
{
if (!string.Equals(cursorPosition, value) // +
{ // +
cursorPosition = value;
NotifyPropertyChanged("CursorPosition");
} // +
}
That is, only raise the PropertyChanged event when the property value actually changes.
You probably want to change your NotifyPropertyChanged method to this:
private void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged; // +
if (handler != null) // ~
{
handler(this, new PropertyChangedEventArgs(propertyName)); // ~
}
}
This is because PropertyChanged could in theory change between the null check and the invocation. You can exclude this theoretical possibility by creating a local copy of the event delegate.
P.S.: To be precise, as Jeffrey Richter points out in his book "CLR via C#", a local variable is still not quite enough: Ideally, you'd assign Interlocked.CompareExchange(ref PropertyChanged, null, null) to handler (instead of simply PropertyChanged) because using that method will prevent the JIT code generator from optimizing away the local variable (IIRC).
I assume you want the PropertyChanged event to fire? You are setting the backing variable's value in Mouse_Move, not the property's value. As a result, the call to NotifyPropertyChanged won't get called.
You shouldn't implement INotifyPropertyChanged on components, controls and forms because databinding will rely on the XXXChanged event paradigm to listen for change notification. Internally, databinding uses property descriptors to listen for change events. They hint how the class detects changes in the documentation for the PropertyDescriptor.SupportsChangeEvents property. This has to do with the history of winforms databinding. XXXChanged was the way to do databinding & change notification before .NET 2.0. INotifyPropertyChanged was introduced in 2.0 in favor of the XXXChanged pattern.
The SupportsChangeEvents property indicates whether value change notifications for this property may originate from outside the property descriptor, such as from the component itself, or whether notifications will only originate from direct calls made to the SetValue method. For example, the component may implement the INotifyPropertyChanged interface, or may have an explicit nameChanged event for this property.
You're setting the Bindable attribute on the field but calling NotifyPropertyChanged with the property as the argument.

WPF: Binding List to ListBox

I have a class:
public class A : INotifyPropertyChanged
{
public List<B> bList { get; set; }
public void AddB(B b)
{
bList.Add(b);
NotifyPropertyChanged("bList");
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
And a binding (DataContext of UserControl is an instance of A):
<ListBox ItemsSource="{Binding Path=bList}" />
Elements are shown, the ListBox is not updated after new object is added to List
After changing list to ObservableCollection and removing the NotifyPropertyChanged handler everything works.
Why the list is not working?
Your property has to be public, or the binding engine won't be able to access it.
EDIT:
After changing list to ObservableCollection and removing the NotifyPropertyChanged handler everything works.
That's precisely why the ObservableCollection<T> class was introduced... ObservableCollection<T> implements INotifyCollectionChanged, which allows it to notify the UI when an item is added/removed/replaced. List<T> doesn't trigger any notification, so the UI can't detect when the content of the list has changed.
The fact that you raise the PropertyChanged event does refresh the binding, but then it realizes that it's the same instance of List<T> as before, so it reuses the same ICollectionView as the ItemsSource, and the content of the ListBox isn't refreshed.
First thought is that you're trying to bind to a private member. That certainly doesn't seem right.
I think that the problem is that, although you are notifying the binding framework that the property has changed, the actual value of the property remains the same. That is to say that although the listbox may reevaluate the value of its ItemsSource binding, it will find that it is still the same object instance as previously. For example, imagine that the listbox reacts by to the property changed event somehow similar to the below.
private void OnItemsSourceBindingChanged()
{
var newValue = this.EvaluateItemsSourceBinding();
if (newValue != this.ItemsSource) //it will be equal, as its still the same list
{
this.AddNewItems();
}
}
In your example, this would mean that it would not reevaluate the items.
Note: I do not know how the listbox works with the ItemsSource property - I'm just speculating!
ObservableCollections send CollectionChanged events not PropertyChanged events
By signaling
NotifyPropertyChanged("bList");
you are basically saying you have a new list object, not that the content of the List has changed.
If you Change the type to ObservableCollection, the collections automatically sends
CollectionChanged
notifications that the collection items have changed, which is what you want.

Categories