c# WPF Threading an OnResponse event to MainWindowViewModel from singleton object - c#

Greetings my smart programming friends!
I have created an OnResponseEvent for an object that is injected into my viewmodel via UnityContainer.
From my injected object class:
public delegate void ResponseEventHandler(AbstractResponse response);
public event ResponseEventHandler OnResponseEvent;
Constructor for MainWindowViewModel:
public MainWindowViewModel(ITrack track)
{
this._track = Track;
track.OnResponseEvent += UpdateTrackResponseWindow;
}
Created delegate to handle the OnResponseEvent in my MainWindowViewModel:
private delegate void HandleTrackResponseCallback(AbstractResponse message);
Since the OnResponseEvent is sending a message, I need to interpret the message in a separate thread and display in a listBox.
Here is where I get confused. If I were using WinForms to write this application, I could use the following code because WinForms knows about my listBox:
if (ListBox.InvokeRequired)
{
var d = new HandleTrackResponseCallback(UpdateTrackResponseWindow);
Invoke(d, new object[] { message });
}
else
lstTrackResponse.Text = Interpret(message); //Interpret is a separate method
However, I am using WPF, and my MainWindowViewModel class does not know anything about my listBox which is located in a view.
Can anyone provide example code how I might handle the OnResponseEvent on a different thread in my MainWindowViewModel class?
Thanks so much, any help is greatly appreciated.

Manipulating the view from the view-model goes against the basic architectural principles of MVVM. Even if it weren't a being called from a different thread it would still not be a wise thing to do.
In MVVM, you would handle this like you do any other data that needs to be displayed in the view:
process and store the data in the view-model itself (using your event handler)
expose it as property including change notification
access that property from the view using traditional data binding
Something as simple as:
<TextBox Text="{Binding Response}"/>
This approach even takes care of the threading problem because now you handle the concurrency issues in the view-model, instead of in the view. Just lock access to the property that TextBox.Text is bound to while you are modifying it.
In general, MVVM avoids ever having a direct dependency of the view-model on the view for several reasons:
the big picture goal of loose-coupling between the view-model and the view
the ability to unit test the view-model without a view
At first this separation might seem clumsy and requires extra work (see above) but it really is worth it and it's what we need to do to get the benefits of the MVVM approach.

Related

Old ViewModels catch events

I am making a Winforms program, using and MVVM-like pattern. All my data is connected to a SessionModel which is passed to all ViewModels (I know this probably isn't the best way to do things, but thats what I got).
My issue is this: Inside a ViewModel I have an event listener, which connects an event to a method, like this:
// Base constructor
public MyViewModel(SessionModel session)
{
this.session = session;
MyUserControl.MyEvent_OnActivate += AddItem;
}
// This method should be called, whenever the event is invoked
private void AddItem()
{
session.Items.AddItem();
}
A new instance of the ViewModel is generated each time the corresponding View is shown. And here arises my problem. Because everything is fine the first time I load the View and ViewModel. But the second time I visit it, the first instance still exists (although not referenced anywhere) and thereby picks up the event as well. The result is that the method AddItem() is called twice (once from each instance of the ViewModel. If I navigate to the View once again, it would be called three time, and so on.
My Viewand ViewModel is loaded from the MainForm like this:
// When called, this method loads the view and view model
private void ShowMyView()
{
MyViewModel viewModel = new MyViewModel(session);
MyView view = new MyView(viewModel);
ShowContent(view);
}
// Clears content panel and shows new view
private void ShowContent(UserControl view)
{
while (pnlContent.Controls.Count > 0)
{
pnlContent.Controls[0].Dispose();
}
pnlContent.Controls.Add(view);
}
Is there some clever way of clearing old instances of view models, since the garbage collection apparently isn't fast enough?
although not referenced anywhere...
Event subscriptions do keep the subscribers to be referenced. The old viewmodel should unsubscribe from MyUserControl.MyEvent_OnActivate whenever a new one is initialized. Make your ViewModel disposable and perform the cleanup in the Dispose method.
I found a solution, by getting rid of the event and simply listening directly to the delegate, as described in this post.
The code then looks like this:
public class MyUserControl
{
internal delegate void MyDelegate();
(...)
}
public class MyViewModel
{
public MyVieWModel(SessionModel session)
{
this.session = session;
MyUserControl.MyDelegate = AddItem;
}
public void AddItem()
{
(...)
}
}
Your problem that MyControl still keeping references to the previous viewmodels.
Winforms perfectly suitable for MVVM pattern. It supports data-binding (not so powerful as in WPF)
I know that I am slaughtering MVVM a bit, using it the way I am. It
was a work around, since my views contained user controls, which I had
to get to "talk to" the view model, which they did not know
By referencing view control in the viewmodel you break MVVM pattern. If you continue to "follow" MVVM - you are on your own, different kind of problems start gathering and after few weeks you decide that MVVM pattern not doable ;)
Simple suggestion for your particular case, without knowing much about application context, user control should now about viewmodels it affect on.
You can bind collection of viewmodels to the user control where it simple calls it's methods
private UserControl_OnActivate()
{
foreach (var viewmodel in ViewModels)
{
viewmodel.AddItem()
}
}
Now user control know about viewmodel and viewmodel know nothing about user control(view) - MVVM pattern.
Old viewmodel's references will be garbage collected when you update ViewModels collection with new ones.

Correct approach when notifying ViewModels of UserControl events in WPF MVVM?

In my WPF View, I'm loading data into User Controls like this:
<ContentControl Content="{Binding ItemEditVm}" />
And then in the ViewModel:
private ItemEditViewModel _itemEditVm;
public ItemEditViewModel ItemEditVm
{
get
{
return _itemEditVm;
}
set
{
_itemEditVm = value;
OnPropertyChanged("ItemEditVm");
}
}
I've got a series of DataTemplates to say which View belongs to which ViewModel. And then in my business logic, I can just spin up a new ViewModel for the UserControl then assign it to the property and all works as expected.
However, to resolve the next task in this application, I need to be able to notify the parent ViewModel of events occurring inside the UserControl. I've done this with a simple event on my child ViewModel and a listener on the parent:
public event EventHandler ItemEditViewModelChanged();
So when I create my ViewModel I can just add a listener:
ItemEditViewModel vm = new ItemEditViewModel(itemId);
vm.ItemEditViewModelChanged += vm_ItemEditViewModelChanged;
And do what needs to be done in vm_ItemEditViewModelChanged().
However, I am instinctively uncomfortable with this. While it doesn't violate any MVVM principles direclty (things are still testable, Views and ViewModels are still separate), it doesn't seem a very flexible way of doing things and it does create undesirable logical links between ViewModel classes.
Is there a better way of doing this? Is my approach to creating and loading UserControls into ContentControls a poor way of creating child controls? Or am I worrying over nothing?
I personally prefer to implement things like this with dependency injection. Typically there will be multiple notifications that need to be made, so start by declaring an interface:
public interface ICustomEventHandler
{
void Event1();
void Event2();
// .. etc
}
Then in the child vm you use dependency injection to inject whatever object needs to watch it:
public class ChildVM
{
[Inject] public ICustomEventHandler Watcher {get; set;}
// .. etc ..
}
First of all this makes mocking very easy, so your unit tests are covered, but more importantly you've formalized the dependencies between this module and the rest of the code and also kept your options open as to how best to implement it. (A simple solution would be for the parent to implement that interface directly and inject itself into the child at creation, in another case you may need to use an intermediate class with singleton scoping or multiple clients).
I am not sure whether this work for you but just my thought.
If you have a MainViewModel which holds your all other ViewModels like the picture above then you can expose Properties/Methods to invoke MainViewModel and Let MainViewModel take the decision to talk to a different ViewModel.

C# WPF MVVM Window OnLoad Binding

My Code behind looks like this...
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MainWindowViewModel();
}
}
My ViewModel looks like this...
class MainWindowViewModel : INotifyPropertyChanged
{
public MainWindowViewModel()
{
bool flag = Application.Current.MainWindow.IsInitialized;
if (flag)
{
// Do something...
}
}
I guess my question is....Does this conform to the MVVM design pattern? The only other way to do this is How to fire a Command when a window is loaded in wpf
I don't know why, but I don't want to use mvvm-light or any other boilerplate code..
Accessing UI component from ViewModel is violation of MVVM pattern.
Application.Current.MainWindow.IsInitialized is breaking that pattern.
Custom behaviours is more in accordance with MVVM. So, i would suggest to go with the approach you mentioned as link in your question.
Accessing UI component breaks the testability of your ViewModel. How would you write testcase for your ViewModel class? Application.Current will be null when you try to test it via unit test and it will throw null reference exception.
One of the main motive of MVVM was to seperate UI logic from business
logic so that business logic can be tested separately without worrying
about its consumer which is view.
There is no "pure" way to do this in MVVM without boilerplate code. In general, you shouldn't need to do work in response to the VIew within your VM - just the concept is a violation of MVVM, since your ViewModel is trying to do something in response the View, and things should always flow the other way.
The ViewModel shouldn't, in a real scenario, care about the View's state at all - it should be doing nothing but presenting data for data binding by the View.
Most of the time when people are attempting this, it's to try to avoid loading data up front. This is something that's typically handled better by pushing the data to load and starting it directly on a background thread within the ViewModel, then updating the property within the VM when it completes. C# 5's async/await language features can be used to simplify this quite a bit.
While it is generally believed that having some load/unload logic is a pattern violation, there is a set of use cases, where it's necessary. E.g. a view model may need to be subscribe to some events. If it didn't unsubscribe when unloaded, it might not be garbage collected, depending on the nature of the subscription.
What would break the pattern is accessing view state from within the view model, e.g. manipulating controls. The role of the view model is to expose data to the view and managing load/unload behaviour is part of this contract. Knowing when a view model is loaded means knowing when to expose that data.
While it is true the view model should not care about state of the view, it must know how to prepare data for presentation in the view. More importantly the view model is a layer between the model and the view that makes them separate. Yet in other words: since 'model' means logic, then 'view model' means logic of getting data to display. And it is also about knowing when to fetch it/make it available/etc.
You may want to take a look at this blog post, which provides a convenient way of making a view model aware of being loaded. It is not 100% correct in terms of MVVM purity, because it passes FrameworkElement back into the view model, but imagine we ignore this parameter.
The sample code below is based on the above blog post, but with purer signatures. You could implement IViewModel interface on your classes:
public interface IViewModel : INotifyPropertyChanged
{
void Load();
void Unload();
}
Then instruct the view to call adequate methods when loaded or unloaded by using an attached property:
ViewModelBehavior.LoadUnload="True"
Notice the last line has its place in XAML - the view is the one that enforces a certain behaviour, not vice-versa.
What you are currently doing is correct and that is how it is really done with other frameworks behind the scenes.
Since you mentioned MVVM-Light, I suggest you can take a look at caliburn micro. It has very nice framework to conform the MVVM Pattern. Caliburn micro makes it easy to hook up bindings with events on the controls. Just check out its documentation and it is still considered as MVVMy..
in particular because MVVM is mainly used to guarantee easy to maintain and testable code, you should bear in mind that Application.Current will be null if you use the MainViewModel in UnitTests. Therefore this code will end in a NullPointerException in your tests.
You should consider using the Initialized event if you want to ensure that something is initialized already. But you create the ViewModel after you called InitializeComponent - I simply would leave the check out.

Calling method of UserControl from ViewModel with Caliburn.Micro

I'm writing a ViewModel-first MVVM application using Caliburn.Micro
My View contains a 3rd party UserControl that implements a Method I want/need to call from the associated ViewModel. How do I do that while still upholding the MVVM principles?
There exists an old thread here on SO where a similar question is asked in a more specific context. I would appreciate it if someone could flesh-out the approaches suggested there a bit.
Approach one suggests that the View could subscribe to an IEventAggregator message. But wouldn't I have to use the code behind file to do that? (I thought that was a big no no in MVVM)
Regarding approach two, I have no idea how to do that. And regarding approach three, thats what I tried first but somehow I didn't quite get it to work.
Let me clarify your understanding:
Yes code in the code-behind is generally avoided, but only because MVVM makes it so easy to bind to viewmodel properties and commands in order to wire up your visual element with the functionality behind the scenes
Code that is view-specific in the code-behind of the view is perfectly acceptable assuming it doesn't cross the boundary of concern. For instance, I have a view in my application that does some visual processing of the page, and to do so I require that there is code in the view. This code may also interact with the viewmodel layer, but it will not directly reference the viewmodel, therefore keeping my components loosely coupled
If you have controls that need particular methods calling, then creating an event aggregator message to propagate the notification to the view is perfectly fine since you are still maintaining the separation of concern between the viewmodel and view (and the application components remain encapsulated and testable)
Example View (I've left all event aggregator wire up code and potential dependency injection stuff out for clarity):
public class MyView : IHandle<SomeNotificationMessageType>
{
// Handler for event aggregator messages of type SomeNotificationMessageType
public void Handle(SomeNotificationMessageType message)
{
// Call a method on one of the page controls
SomePageControl.SomeMethod();
}
}
Obviously, what you wouldn't do is something like this in the ViewModel:
public class MyViewModel : IViewAware
{
public void DoSomethingThatAffectsView()
{
var view = this.GetView() as MyView;
view.SomePageControl.SomeMethod();
}
}
Which violates the MVVM principles since you are tightly coupling MyViewModel and MyView.
What if you wanted to use the Context property in caliburn micro which allows multiple views over the same view model? The code above would break - even if you checked the View type, you would still end up with spaghetti code e.g.
public class MyViewModel : IViewAware
{
public void DoSomethingThatAffectsView()
{
var myview = this.GetView() as MyView;
if(myview != null)
myview.SomePageControl.SomeMethod();
var myotherview = this.GetView() as MyOtherView;
if(myotherview != null)
myotherview.SomePageControl.SomeMethod();
// ad infinitum...
}
}
Of course this is subjective: it may be that your usercontrol affects the viewmodel and the view in a complex way, in which case you might want to consider looking at the architecture and working out how that usercontrol can better fit
Have you got any background on what the UC is and what the method on it does?

Calling a Method in View's CodeBehind from ViewModel?

I have a method within the code behind of my View (this method does something to my UI).
Anyway, I'd like to trigger this method from my ViewModel. How could this be done?
My (and maybe others?) difficulty with MVVM was to understand a simple thing: View knows about ViewModel. I was using bindings and commands, but they are simple strings in xaml. Because of safe resolving at run-time (safe means you can do a typo, but software will not crash) this makes view decoupled from view-model (at compile time at least). And I was always looking for solution to keep this decoupling, to example, behaviors.
Truth is, you can get access directly to view model, which is typically a DataContext of window/user control:
var vm = (MyViewModel)this.DataContext;
Knowing that, using events probably the best way to call view method from view model, because view model don't know if there is subscriber, it just firing that event and event can be used by view or another view model.
// define in the view model
public delegate void MyEventAction(string someParameter, ...);
public event MyEventAction MyEvent;
// rise event when you need to
MyEvent?.Invoke("123", ...);
// in the view
var vm = (MyViewModel)DataContext;
vm.MyEvent += (someParameter, ...) => ... // do something
You can do it like this in View (code behind).
It casts to an interface to be implemented by the ViewModel, so that you are not constrained to one specific ViewModel type.
// CONSTRUCTOR
public SomeView()
{
InitializeComponent();
DataContextChanged += DataContextChangedHandler;
}
void DataContextChangedHandler(object sender, DependencyPropertyChangedEventArgs e)
{
var viewModel = e.NewValue as IInterfaceToBeImplementedByViewModel;
if (viewModel != null)
{
viewModel.SomeEvent += (sender, args) => { someMethod(); }
}
}
According to MVVM pattern ViewModel is not aware of View, so this is not acceptable. To interact with ViewModel View could trigger a command, also you can use bindings. Moreover, you should not move UI-specific things like BusyIndicator to ViewModel level.
Please provide more details regardign your concrete use case - when you want to call a View's method and what this method does.
Let's say you have a method within the code behind of my Login View, that updates UI by bringing Focus to the PasswordEntry if login fails, then the easiest & most universal way to trigger this method from your ViewModel is using Action delegates.
As you can see in this sample, all you need to add, where your services determine that the login has failed and you want the Password Entry to get the focus, is two lines of code in your ViewModel and an action handler in your View.
ViewModel code:
Declaration of the event: public Action<bool> OnLoginFailed { get; set; } &
Then simply, when needed, executing this OnLoginFailed?.Invoke(true);
View code:
ViewModel.OnLoginFailed = ((obj) =>
{
PasswordEntry.Focus();
});
Update: I wrote an article to explain this in a lot more detail
I saw youre reply to the answer above, you are saying that you want your ViewModel to retrieve data and then tell your view to stop the busy indicator.
I'm not sure if my solution would be the best solution, but you can give it a try, and maybe someone can correct if I'm wrong.
So from your view, you would call a method from ViewModel to start reading the dataset, am I right? In this method, you can pass a delegate (pointing to a method that exists in your view) and when your ViewModel finishes reading the dataset from the server, trigger the delegate (from your viewmodel) that is linked to your method in your view that can stop the busy indicator.
so in your view you have
void StopBusyIndicator()
{
this.BusyIndicator.IsBusy = false;
}
and when you call your ViewModel to read dataset,
call it like this:
ViewModel.ReadDataSet( ()= >StopBusyIndicator)
which will pass the StopBusyIndicator method as a delegate, which you can call at the end of your ReadDataSet.
HTH
You could write an action class that accepts a Data Transfer object. Within the DTO, add a property called "View" and assign it the current view. Call the action via the controller from within your view's codebehind, unbox the DTO and now you have full control of the view within the action class.
If you truely want to do this in your model, just create the method with a "View" type parameter in your Model and execute it, passing in the current view.

Categories

Resources