MVVM Light View not refreshing binding property - wpf

I use MVVM Light.
My Model inherits from MVVM Light's ObservableObject.
The Model has a property X
public float X
{
get
{
return x_;
}
set
{
Set<float>(() => this.X, ref x_, value);
}
}
In my ViewModel I have a property X
public float X
{
get
{
myModel.X;
}
}
My View has a label where the content is binding to the ViewModel property X.
(DataContext is set to ViewModel)
When the value of property X in Model is updated from code, the label in the view never gets updated.
Question what is the recommended way to make sure that the View correctly reflects the updated value?
(If I make a property in my ViewModel that returns the Model, I could bind direclty to Model.X in my View. But I want my View to bind to the ViewModel not directly down to the Model)

When myModel.X fires the PropertyChanged event, that does not automatically fire the ViewModel's PropertyChanged.
Moreover, if your Model class already implements INotifyPropertyChanged, there is no need to duplicate the X property in the ViewModel class.
Just turn the myModel member into a public property
public class ViewModel
{
public Model MyModel { get; set; }
}
and bind to it by {Binding MyModel.X}.

Related

Passing data between View models using Prism Event Aggregator

I have a user control whose DataContext is bound to its view model which should display Status Messages from any other UserControls which are bound to their respective view models.
Status Messages is an ObservableCollection<StatusGridModel>. Now I am trying to use EventAggregation in order to pass this collection from my different view models to StatusViewModel.
In the constructor of every view model I have IEventAggregator of Prism resolved by Unity. Now on ButtonClick in first ViewModel I am doing the following:
DashBoardStatusCol.Add(statusGridModel);
eventAggregator.GetEvent<StatusEvent>().Publish(DashBoardStatusCol);
where StatusEvent class derives from PubSubEvent
public class StatusEvent : PubSubEvent<ObservableCollection<StatusGridModel>>
{
}
Below is my second view model where the Status Messages should be displayed. I have subscribed to my StatusEvent class in the constructor.
public class StatusGridViewModel : ViewModelBase<PresentationModel>
{
IEventAggregator eventAggregator;
public StatusGridViewModel(IEventAggregator eventAggregator)
{
this.eventAggregator = eventAggregator;
this.eventAggregator.GetEvent<StatusEvent>().Subscribe(SetStatus, true);
}
private void SetStatus(ObservableCollection<StatusGridModel> collection)
{
StatusCollection = collection;
}
private ObservableCollection<StatusGridModel> statusCollection;
public ObservableCollection<StatusGridModel> StatusCollection
{
get { return statusCollection; }
set { statusCollection = value; }
}
}
Now my problem is the subscribed event SetStatus is never called when the button is clicked in the first view model.
What am i missing? Should my ObservableCollection implement INotifyPropertyChanged and on the setter of property I should publish my event?
Should my ObservableCollection implement INotifyPropertyChanged and on the setter of property I should publish my event?
StatusCollection should raise the PropertyChanged event, so the view knows it should update its bindings. ObservableCollection only works if the content is updated (Add, Remove...), not if you replace the whole collection.

How to indirectly set a binding?

I've seen enough examples with binding to property A with a datacontext where A exists in the viewModel class. Now what if in the viewModel I do not have any property A, instead I create some calss B that contains property A, then how to set up a binding here?
Let's say in xaml<TextBlock Text="{Binding Bid}"..> and In the viewModel's constructor I set up
Quote b = new Quote();
HttpClient.QuoteMap.Add(1,b);
HttpClient.Socket.reqMktdata(1,contract,..)
So b keeps updating its Bid and Ask... The thing is I don't see how to set a binding to b's Bid. For listview or DataGrid I can see how to do it as there's a property called itemsource to specify the data binding source and for each column different property is bind to any property if needed.
The class itself needs to be a property.
<TextBlock Text="{Binding Path=MyClassToBind.PublicProperty}"
private MyClass myClass = new MyClass();
public MyClass MyClassToBind
{ get { return myClass; } }
In your viewmodel create a property A which has the notify event on its change, but get the data from the B instance. If B has INotifyPropertyChanged, then subscribe to those changes and when B event fires that a change has occurred, post the notified change for your property A such as
OnPropertyChanged("A");
That way you can have related data which exists elsewhere but still updates the view accordingly.
This will update when the B property Data changes, to the property A on the MVVM.
class MyMVVM : INotifyPropertyChanged
{
private TheBClass B { get; set { OnPropertyChanged("A"); } }
public string A
{
get { return B.Data; }
set { OnPropertyChanged("A"); }
}
public MVVM(TheBClass bInstance;)
{
B = bInstance;
B.PropertyChanged += (sender, args) =>
{
if (args.PropertyName == "Data")
OnPropertyChanged("A");
};
}
}

WPF: Data Binding with an ObservableCollection passed as parameter in a UserControl constructor

I have a UserControl with a ComboBox in it and I'm binding an ObservableCollection to it such as follow. Right now the collection is populated in the UserControl. However, I would like to create the ObservableCollection in the MainWindow and have another constructor for my UserControl. here's what I got now and it's working:
public ObservableCollection<ComboBoxInfo> Items { get; private set; }
public CustomComboBox()
{
InitializeComponent();
Items = new ObservableCollection<ComboBoxInfo>();
cmb.ItemsSource = Items;
if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
{
this.createNameComboBox(); // ObservatoryCollection populating
}
}
I tried implementing a second constructor and moving the collection populating function in the Main Window but I get an error saying my comboBox in the UserControl is not set to an instance of an object. Ideally I would like something like this:
public CustomComboBox(ObservableCollection<ComboBoxInfo> Items)
{
this.Items = Items
// Not sure if the binding should be done here or in default constructor
}
Any idea how to properly do this ? Thanks
Your solution should include a ViewModel which would be set as a DataContext of your User Control.
This ViewModel should contain and expose the ObservableCollection as a public property, ideally it should use some injected service provider to obtain the data from some data store and populate the ObservableCollection with that data, Finally, the ComboBox from your User Control should bind to that ObservableCollection in the ViewModel.
Your User Control code-behind should have no code other than some event handlers to manipulate the UI in response to UI events if necessary...
That is how things are done properly in WPF utilizing the MVVM pattern.
Here is an example of how a service is injected into the VM constructor and used to populate a collection with some data:
public class MainWindowViewModel
{
private ICustomerService _customerService;
public MainWindowViewModel(ICustomerService customerService)
{
_customerService = customerService;
Customers = new ListCollectionView(customerService.Customers);
}
public ICollectionView Customers { get; private set; }
}

Multiple Binding

In my WPF Caliburn.Micro application, I have a datagrid and a checkbox with a corresponding ModelView bool property. I need to bind the checkbox to one of the datagrid's fields OneWay (which is easy). But also I want to bind the same checkbox to the property OneWayToSource. Could you please tell me how I can do that? I don't see how Multibinding can help here.
Thanks.
I don't know if this is a checkbox per row of the DataGrid, or a checkbox for a row with a particular id or index. Either way, you can use TwoWay binding, which will be the default anyway if your view model property has a getter and setter.
Your view model property should point to the instance of the record that the DataGrid is binding to.
E.g.
View Model
public ObservableCollection<Item> MyGridItems { get; set; }
public MyViewModel()
{
this.MyGridItems = ...
this.MySpecialItem = this.MyGridItems[0];
}
public Item MySpecialItem
{
get { return this.mySpecialItem; }
set { this.mySpecialItem = value; // notify of property change here }
}
View
<CheckBox IsChecked="{Binding MySpecialItem.MyBooleanProperty}" />

UI Binding updates to a ObservableCollection that gets re-assigned

Description:
First I created an ObservableCollection which is accessed via the public property MyCollection. Now if I bind my DataGrid UI to MyCollection it will recognize collection changes, but not if MyCollection itself changes (ie. UpdateCollection method). To solve this issue I applied the familiar 'PropertyChanged("MyCollection")' to the MyCollection Property.
Now I found the need to group my DataGrid Content which requires a Collection View layer. When I added and binded to the CollectionView the UI no longer updates when MyCollection gets re-assigned. I read that only CollectionChanged propagate from the Source to the View. I guess in my case it is the PropertyChange on MyCollection that needs to somehow trigger a CollectionChanged event on the Source or View.
Question:
How can I get a re-assigmend on MyCollection to trigger a UI update, which is bound to a View of MyCollection?
Note: The reason for re-assigning MyCollection is due to a Modular MEF/MVVM architecture.
public class MyViewModel
{
public MyViewModel()
{
MyCollectionViewSource = new CollectionViewSource() { Source = MyCollection};
// The DataGrid is bound to this ICollectionView
MyCollectionView = MyCollectionViewSource.View;
}
// Collection Property
// NotifyPropertyChanged added specifically to notify of MyCollection re-assignment
ObservableCollection<MyObject> _MyCollection;
public ObservableCollection<MyObject> MyCollection
{
get {return _MyCollection;}
set {if (value != _MyCollection)
{_MyCollection = value;
NotifyPropertyChanged("MyCollection");}}
}
public MyCollectionViewSource PropertiesCollectionViewSource { get; private set; }
public ICollectionView = MyCollectionView { get; private set; }
// Method updates MyCollection itself (Called via ICommand from another ViewModel)
public void UpdateCollection(ObservableCollection<MyObject> NewCollection)
{
MyCollection = NewCollection;
}
}
Thanks,
Have a look at the Active Grouping Collection, its aimed at a different problem but might solve yours.
Building a smarter WPF CollectionView
Active Collection View on CodePlex

Resources