Silverlight/Windows Phone ViewModel updating question - silverlight

I have a XAML page whose DataContext is set to my ViewModel. A switch control on the page is bound to the following code in the ViewModel:
public bool TeamLiveTileEnabled
{
get
{
return Data.Subscriptions.Any(s => s.TeamName == this.Team.Name);
}
}
When this page is initialized, Data.Subscriptions is an empty list. I retrieve the list of subscriptions through an async web service call, so it comes back after the getter above is called.
When the web service call comes back, Data.Subscriptions has items added to it, and I'd like the UI to update based on the new result of the LINQ expression. Right now nothing happens, and I confirmed that Data.Subscriptions contains items that satisfy the condition above.
Data.Subscriptions is an ObservableCollection of Subscription items.
Can someone point me to what to do? Thanks!

The problem is that your ViewModel is not aware of any changes to the ObservableCollection. Within the ViewModel, subscribe to the CollectionChanged event of Data.Subscriptions.
Data.Subscriptions.CollectionChanged += SubscriptionsChangedHandler;
Within the event handler notify listeners of TeamLiveTileEnabled by sending a PropertyChanged notification
NotifyPropertyChanged( "TeamLiveTileEnabled" );

Related

WPF telerik GridView aggregate is not updating until focus out of a grid view field

telerik:GridView, using aggregate function to show sum in footer, the property is being updated from somewhere else and GridView is not calling PropertyChanged until focus out from GridView Column.
How we can refresh aggregate as soon as Item-source Property is changed.
I want to get aggregate updated as soon as ItemSource Property is updated.
On GridView property change I am using
private void GV_PropertyChanged(object s, PropertyChangedEventArgs e)
{
GV.CalculateAggregate();
}
According to the docs, it seems like you should raise the CollectionChanged event for the source collection:
In order to get the aggregate results refreshed, you have to notify
the GridView that the bound collection has been changed. A
CollectionChanged notification of the bound collection should be
raised.
There are four possible solutions:
You can update the value as illustrated in this help article on how to
edit an item outside RadGridView.
Ensure that a CollectionChanged event is raised from the bound source
collection.
Invoke RadGridView.CalculateAggregates() method.
Invoke RadGridView.Rebind() method. It will raise CollectionChanged
notification with action Reset. Please note that the entire view will
be recreated.

How can I launch an async prompt to confirm updating SelectedItem in a WPF ListBox?

I have a ListBox bound to an ObservableCollection of objects. Selecting object loads it into the UI for editing and saving.
I would like that when selecting a new object in the ListBox that there is a prompt if there is unsaved changes UI so a check needs to occur when the ListBox selection changes and a prompt appears to confirm the change - if the change is confirmed then it happens as normal otherwise the change is prevented/undone.
The prompt code is an async method that returns a Task and so it cannot occur in a setter - it can occur in an event though which I have had limited success with.
It seems we only have access to SelectionChanged event. I can prompt here but when reverting the SelectionChanged event is fired again to result in an infinite loop.
Given that this is probably quite a common pattern - what is the best practice way to handle this?
Add a method that calls your prompt code as you call it and then returns the value. After that, you can simply call that method from the setter of the property that is data bound to the SelectedItem property:
public YourDataType CurrentItem
{
get { return currentItem; }
set
{
if (isChangeConfirmed)
{
isChangeConfirmed = false;
currentItem = value;
NotifyPropertyChanged("CurrentItem");
}
else GetIsChangeConfirmed(value);
}
}
public async void GetIsChangeConfirmed(object value)
{
isChangeConfirmed = await YourAsyncPromptMethod();
if (isChangeConfirmed) CurrentItem = value;
}
private bool isChangeConfirmed = false;
UPDATE >>>
Actually, as you correctly pointed out, there are some restrictions over the use of async methods. To get around that, you can set the confirmation value to a variable that you check inside the setter as shown above, instead of returning it from the method.

Make View Models activation aware in Prism/Composite MVVM WPF application

In my MVVMC application I have a process which contains multiple steps, basically a wizard.
My controller resolves my outer View (call it WizardView) and adds it to the main region.
WizardView contains a breadcrumb trail to show the progress through the wizard and a sub Region to load other views into (call this WizardRegion). Step1View is the first View loaded into WizardRegion.
Each view has it's ViewModel injected into the constructor using the Unity container.
WizardViewModel subscribes to several event aggregation events which are published by the step view models.
As each step is completed the View Model publishes an event which WizardViewModel uses to store the state, this means WizardViewModel is collecting the data from each step as we progress. The step ViewModel also calls the controller to load the next step into WizardRegion.
At the final step WizardViewModel saves the result of the wizard and the MainRegion is navigated back to some other screen.
The next time we enter the wizard, we create a new instance of all the Views and ViewModels but the event subscriptions from the previous wizard still exist.
How can I make my view models aware that they're de-activated so I can unsubscribe my events?
Another option would be to unsubscribe from the event in the event handler. This will probably work but will add complexity when I step back in the wizard and need to re-subscribe to the events again.
The solution is to implement Microsoft.Practices.Prism.IActiveAware in my View Model.
public bool IsActive
{
get { return _isActive; }
set
{
if (_isActive != value)
{
_isActive = value;
DoActiveChangedWork(value);
}
}
}
public event EventHandler IsActiveChanged;
It's also possible to implement this in the View but it's not a requirement.
If you are talking about Prism EventAggregator - you can set keepSubscriberReferenceAlive parameter to false so it will use a weak reference under the hood so everything will be "unsubscribed" automatically by GC when an object will "die".
fundAddedEvent.Subscribe(FundAddedEventHandler, ThreadOption.UIThread, true);
otherwise you have to do it yourself by explicitly unsubscribing:
fundAddedEvent.Unsubscribe(FundAddedEventHandler);

wpf binding: The calling thread cannot access this object because a different thread owns it

I am getting this error after raising NotifyPropertyChange event from a view model property.
I added (as a test) an UI Dispatcher.Invoke call on the setter which seems to have fixed the problem temporarily.
public FeedTrackingSummary SelectedFeedTracking {
get { return _selectedFeedTracking; }
set {
Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)(() => {
_selectedFeedTracking = value; Notify("SelectedFeedTracking");
}));
}
}
SelectedFeedTracking below is set by choosing a dropdown value which is bound to this property:
<ComboBox... SelectedItem="{Binding SelectedFeedTracking}" />
the error happens after selecting a drop-down value. There is no other code setting this property. I guess my viewmodel is used in a background thread at the time this happens?
UPDATE
i tried removing the call to INotifyPropertyChanged, and set a totally different property, and the error still persists. so i guess this has to do with the accessibility of the whole viewmodel ?
set {
SelectedCalc = -1;
}
Some MVVM Frameworks (such as Caliburn.Micro, for example) have a base NotifyPropertyChanged class which automatically marshals property change notifications (by raising the PropertyChanged event) to the so-called "UI Thread".
So, instead of having to Application.Current.Dispatcher.Invoke(...) on every property setter, put that code in your Notify() method. Thus making sure every time you notify property changes in the ViewModel you do so in the UI thread.

wpf mvvm binding List<int> to Listbox from background thread

I'm pretty new to wpf and mvvm so this may be a easy question but I'm hoping someone can explain it to me. I have a class in my model that all it does is polls processes and if it see that "calc" is running it adds it process id to a List. If you close calc.exe it removes it from the List. If the List changes it fires and event. In my ViewModel i subscribe to that event and update my property that fires off PropertyChanged. Now if my Property is a List in the view model then my binding in my view does not update correctly. If I changed my List to an ObservableCollection in my Model and ViewModel then i get a cross thread issue. However, if i leave my List in my model and change my property in my ViewModel to a ObservableCollection and copy the values of the the list into an observable collection everything works as expected.... I don't get it, do i really need to do the copy to get the binding in my ListBox to work properly?
Take a look at the DispatcherNotifiedObservableCollection that Cinch implements. It will automatically use the Dispatcher if need be. Read this article to see the code for it:
http://www.codeproject.com/KB/WPF/CinchIII.aspx#ObsCol
You need to update the observable collection from the dispatch thread.
Something like (not technically/syntactically correct, but psuedo-close)
Dispatcher.BeginInvoke( () => theList.Add( theThing ) );
A better way to achieve this functionality, is expose the Model via a property in the ViewModel, and bind the ListBox to Model.ObservableList. And use John's suggestion when adding and removing items to this list. This will not require you to copy the values from list to an observablecollection.
So your viewModel code would like
public class ViewModel
{
public Model Model { get { return _model; } }
}
The binding in xaml:
<ListBox ItemsSource=Model.ObservableList/>
where the ObservableList property returns your ObservableCollection.
As all UI elements in WPF have thread affinity (to the Dispatcher thread), any updates to the UI should be marshaled via the Dispatcher. You can marshal calls via the Dispatcher, using Dispatcher.Invoke. In this case, your view, viewModel and Model reside in the Dispatcher thread, so any call to update the UI via the viewModel or Model, would require you to call Dispatcher.Invoke.

Resources