Currently I have 2 ViewModels in my project. MainViewModel is currently bound to my WPF window, so I have a command in my other ViewModel (AdventurerViewModel) that doesn't fire anymore. Is there a way to have that command fire without the ViewModel being bound or do all of my commands need to be in MainViewModel? And is there a good way to organize commands that might help me avoid this situation in the future? Any advice would be greatly appreciated.
EDIT: A bit of code
From my XAML
Button Grid.Column="3" Grid.Row="1" Content="IncreaseLevel" Command="{Binding IncreaseLevel}"
AdventurerViewModel.cs
public ICommand IncreaseLevel { get { return new RelayCommand(IncreaseLevelExecute, CanIncreaseLevelExecute); } }
private bool CanIncreaseLevelExecute()
{
return true;
}
private void IncreaseLevelExecute()
{
Level++;
}
First make sure you split the ViewModels correctly and have the commands in the correct ViewModels.
After that it might still be possible that you want to notify other ViewModels of changes in a current ViewModel. In that case you could have a look at a messaging system between ViewModels so a ViewModel can subscribe to a specific event and respond to it.
Use one ViewModel per View. If you use a Window then you should use one ViewModel. Right now in my project a have a Window which has 2 user controls in it, and each UserControl has its own ViewModel plus the ViewModel for the Window. I could put everything in one ViewModel but it is cleaner this way, but for your example I recomend you put everything in one ViewModel. It realy depends on situations or project requirements.
Related
At first: This App and Question is for learning purpose
I'm on a new application and facing the problem that I want to open a Window when the user clicks on a Button in the MainView. In the past I'd have designed a Command which just creates the new Window and displays it
new RelayCommand((x)=>new SecondWindow().Show());
Now with this new Project I'm trying to fully decouple all classes from each other. To achieve this my App consists of 4 Assemblies (BL, COM, DAL and UI).
As in each WPF Application, the App starts with the MainWindow.xaml. The MainWindow.cs will create it's instance of MainWindowViewModel:
public ViewModel VM {get; private set;}
public class MainWindow(){
VM = new ViewModel();
InitializeComponent();
}
(which already violates loose coupling) (Any tips on how to make it better?)
My last attempt is to create an instance of my second Window inside my main window
<Window.Resources>
<local:SecondWindow x:Key="sw"/>
</Window.Resources>
and pass it as a CommandParameter to my Command
CommandParameter="{StaticResource sw}"/>
new RelayCommand((x)=> ((Window)x).Show());
This solution works but has one big disadvantage - the second window get's created immediately after the app starts - and so does it's ViewModel which starts some heavy processes (DB Connections etc.)
I've heard something abour IoC principle but I really don't know how to use it with an wpf application.
You are thinking along the right lines.... you basically have to create a List of ViewModels as your application starts up, then you can switch between them as the user presses buttons and pass the name of the ViewModel as a CommandParameter to your Command handler....
You might find this link to Rachel Lim's Blog
https://rachel53461.wordpress.com/2011/12/18/navigation-with-mvvm-2/
Also, I'm not going to post any code here coz it simply gets too complicated. So here is a download to just about the simplest example I could come up with
http://www.mediafire.com/download/3bubiq7s6xw7i73/Navigation1.rar
Download and un-RAR it (with win RAR) You will need to step though the code, figure out what its doing and how its doing it then modify it to suit your needs... Or modify your needs to suit the code.....
The example is a modification of Rachel Lim example. It simply contains Views and ViewModels, there are no Models or data. It demonstrates switching between two different Views.
UPDATE 1
With specific reference to the demo code.... Your VMs are added to a static collection of VMs (see AddViewModel function), each View ( the DataTemplate associates View with ViewModel) is selected when you click a button for example, by calling 'SelectViewCommand' which in turn sets Current_ViewModel to the selected ViewModel... the corrisponding ContentControl is then updated to display that currently selected View...
I know is confusing and very difficult to explain
When you press a button to 'change Views' you are actually changing the value of the property that your ContentControl is bound to, so you have to call the correct SelectViewCommand in the SAME instance of the class that your ContentControl is bound too...
In the demo you'll see that in the 'LogOn_View' I call
Command="{Binding DataContext.SelectViewCommand, ElementName=Base_V}"CommandParameter="Main_ViewModel"
Here I am calling the SelectViewCommand in the Base_ViewModel (x:Name="Base_V" in Base_View XAML), That's because I want to change the View that is displayed in the Base_View's 'ContentControl'
In Main_View I call
Command="{Binding SelectViewCommand}" CommandParameter="MainV1_ViewModel"
Here I am calling the SelectViewCommand in the Main_ViewModel, That's because I want to change the View displayed in the MainView's 'ContentControl'....
I typically create a WindowService class for managing window changes/dialogs in MVVM. Having "View" code in the ViewModel (i.e. Window.Show()) goes against MVVM principles. For example:
public class WindowService : IWindowService
{
public void ShowDialog<T>(ViewModelBase viewModel) where T : IApplicationDialog
{
IApplicationDialog dialog = (IApplicationDialog)Activator.CreateInstance(typeof(T));
dialog.Show();
}
}
And then your call from the ViewModel would look something like:
windowService.ShowDialog<SecondWindow>(new SecondWindowViewModel());
If you're using DI, you can pass a reference to the IoC container to the window service and create the window instances from that rather than using Activator.CreateInstance (i prefer the DI approach personally)
I want to clear some issues about MVVM violation.Becuase of this i've created a solution with some projects to demonstrate the cases.
Here's the definition (Projects) of the solution :
View (its a WPF Class Libraray and obviously it has the views)
ViewModel (its a Class Libraray and obviously it has the viewmodels )
Model (its a Class Libraray and obviously it has the models)
Domain (its a Class Libraray and it has the application dataModels )
Core (its a Class Libraray and it has the core of wpf like RelayCommnd or EventToCommand)
Application ( its a wpf application and the startup project)
ExternalCustomControl (its a wpf custom control library created by an imaginary third party company)
I Offer you to download the whole solution to understand better from
Here
First Issue :
I've an EventToCommand in the MainWindow.xaml for Closing Event of the window and attached it to MainWindowClosingCommand with the PassEventArgsToCommand set to True,then,in the MainViewModel there's a handler for the command named OnMainWindowClosing
private void OnMainWindowClosing(object parameter)
{
var arg = parameter as CancelEventArgs;
// What is the best way to show message dialog to user?
// Do i have to send message to the View to show the messageBox dialog and then the window send me the answer back to continue?
// What about IMessageBoxService? Doesn't it violates MVVM?
// Doesn't following code violates the MVVM?
// Cancel the Closing of a Window isnt a UI side duty?
arg.Cancel = true;
}
and totally whenever you want to set e.Handled or e.Cancel you face this issue.So do you know any other way that doesn't need to cast parameter as CancelEventArgs ?
Second Issue :
I've an EventToCommand in the MainWindow.xaml for PreviewMouseDown Event of the Grid and attached it to MouseClickCommand with the PassEventArgsToCommand set to True,then,in the MainViewModel there's a handler for the command named OnMouseClick:
private void OnMouseClick(object parameter)
{
// var arg = parameter as MouseButtonEventArgs;
// This is the violation of MVVM : To cast the parameter to MouseButtonEventArgs i have to add a refrence
// to PresentationCore.dll in the ViewModel Project
// The next and worse step is that in most cases we need to know the Original Source of the event
// (maybe its a StackPanel or a Label or etc) and this again vioaltes the MVVM
// So Whats the WorkAround?
}
Third Issue :
I used the ThirdParty Control(Imagine Infragistics or DevExpress or any other third party control but here as an example i created the imaginary control in my solution as the ExternalCustomControl Project) in my MainWindow Like this :
<thirdParty:ThirdPartyCustomControl Grid.Row="1"
ItemsSource="{Binding MyItemsSource,Converter={StaticResource converterKey}}" />
and ThirdPartyCustomControl has a property of type IEnumarabe<CustomControlDataModel> (CustomControlDataModel is a type that exists in the ExternalCustomControl assembly) But as you know if you want to create a property in MainViewModel for the control with the type CustomControlDataModel you have to add a refrence to ExternalCustomControl.dll in ViewModel Project and this violates MVVM so i created a type named MyDataModel and bound the ItemsSource of the control to MyItemsSource property in MainViewModel :
// If i define MyItemsSource as List<CustomControlDataModel> i have to add a refrence to ExternalCustomControl.dll
// and i think its again violate the MVVM (because ExternalCustomControl.dll is a UI Side Controls Assembly)
public List<MyDataModel> MyItemsSource { get; set; }
so i bound a property of type CustomControlDataModel to a property of type MyDataModel and of course i need a Converter :
public object Convert(object value, Type targetType, object parameter, c System.Globalization.CultureInfo culture)
{
// Imagine when the source data (MyDataModel) is huge (for example 1 milion) it (this dummy Conversion)
// affects the performance
if (value is List<MyDataModel>)
{
var result = new List<CustomControlDataModel>();
(value as List<MyDataModel>).ForEach(myVal =>
{
var custDataModel = new CustomControlDataModel();
custDataModel.ID = myVal.ID;
custDataModel.Name = myVal.Name;
custDataModel.Age = myVal.Age;
result.Add(custDataModel);
});
return result;
}
return value;
}
and the question is do you know any better way than this dummy conversion or you normally add your third party assemblies to your view and viewmodel both?
These are the issues that i've faced and i'll be appreciated if you add more if you know the other issues and share your expertise to everyone.
Upadte:
For the MessageBox Part of first issue i suggest this link
MesageBox
Thanks.
Excellent questions!
1) I personally believe you are correct, the use of a service violates MVVM. I wrote a very lengthy article on this exact topic a few weeks ago titled Implementing Dialog Boxes in MVVM. In that article I make the case for a "pure" solution to the overall problem of MVVM dialog boxes but it took 11 pages to explain how I arrived at that design. Fortunately the actual implementation is very straightforward, is similar to data templating, supports the multiple-project design you've specified and it works with 3rd party libraries. Have a read, I always appreciate objective feedback.
2) If you're using MVVM Lite then EventToCommand allows you to specify an argument converter. Here's an example where I used it to convert the window mouse move message argument to an equivalent representation in my view model:
<i:EventTrigger EventName="MouseMove">
<cmd:EventToCommand Command="{Binding ElementName=_this, Mode=OneWay, Path=MouseMoveCommand}" PassEventArgsToCommand="True" EventArgsConverter="{StaticResource MouseEventArgsConverter}" />
</i:EventTrigger>
3) If I understand your question correctly I add a reference to both the view and view model projects, at least when that is my project structure. To be perfectly honest though I usually place my view and view models in the same project e.g. MyProject.UI, with everything sorted by category folders. I saw this done during a contract I was working on for a major international firm and in practice it works really well because you typically edit a view and it's corresponding view model at the same time; having them side-by-side in the solution window really does make the whole development process easier. Obviously some purists don't like it much, but personally I don't believe that simply having them in the same project breaks MVVM provided you still adhere strictly to that architecture. I've also never had it create any problems with unit testing etc where you need to create view models only.
my closing code looks like this, i dont think that is violating mvvm
xaml
<Window>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Closing">
<cmd:EventToCommand Command="{Binding ClosingCommand}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
mainviewmodel.cs
public ICommand ClosingCommand
{
get
{
return this._closingCommand ?? (this._closingCommand = new DelegateCommand<CancelEventArgs>((args) =>
{
//i set a property in app.xaml.cs when i shut down the app there with
//Application.Current.Shutdown();
if (App.IsShutDown) return;
if (this.HasChanges)
{
var result = _msgService.Show("blup blup", "blup", MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No);
if (result == MessageBoxResult.No)
{
args.Cancel = true;
}
}
else
{
var result = MessageBox.Show("Blup blup", "blup", MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No);
if (result == MessageBoxResult.No)
{
args.Cancel = true;
}
}
}));
}
}
third issue (ThirdParty Control): i dont get your problem if the control need a type of collection then expose these colelction through your VM.
second issue: well is hard to say. i use something like this, and i would say is mvvm like ;)
<DataGrid x:Name="myGrd">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<Commanding:EventToCommand Command="{Binding Path=OpenCommand}"
CommandParameter="{Binding ElementName=myGrd, Path=SelectedItem}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
and at the end i do mvvm but always in mind to do things simple
For your second issue I think you just need to rethink what it is you are trying to achieve and why.
If you are wiring up a handler on a grid, and then making decisions based on what specific UI element of that grid was clicked in code you are probably doing things wrong. A Command called OnMouseClick is a bit of a code smell too, because that command says nothing. A command would be something like UserSelectedCommand, or GrapefuitSliceRequestedCommand ... i.e. much more specific than just a general 'something was clicked'.
You want to try and break that 'something' down into the logic for issue a clear and definitive command at that point rather than trying to work with MouseClickEventArgs and deciding in code what that means - your UI should be deciding what that means, and issuing commands to your VM.
So your individual UI elements should have the commands and binding, rather than trying to set commands at the layout UI level. If an Image is clicked that means something specific, if a row of a DataGrid is clicked that means something specific, and if a Slider is dragged that means something specific. Create your XAML so that it triggers those specific commands and don't push that responsibility up to a vague 'my whole ui was clicked and now I will use code to find out what exactly' way of thinking.
Once I found out MVVM I really liked it. The whole concept of binding, separating view from logic, testability, etc was very encouraging. It was a nice alternative for the messy, never-ending code behind. Than I learned there are commands that can be bound, which I also liked at first.
Having written a couple of controls using MVVM though I found out that my view models start to look more or less like code behind. Full of commands that did almost exactly what was previously done in code behind by event handlers.
Let me give you some examples.
There is a control with a button "Details" which opens another window.
[approach 1]
The first (and worst) thing you can do is call something like this in your command:
new DetailsWindow().ShowDialog();
That makes the view model strongly reference the presentation layer - ugly.
[approach 2]
Lets fix this problem using a weak reference and create something like IDialogService. We can inject a simple implementation that creates and opens the window. Now we got rid of the strong reference to the presentation layer and the command can look like this:
_dialogService.ShowDetailsWindow();
I still don't like this approach. To me it feels like the view model is not something that should decide whether to show a window or not. It should serve and handle data.
[approach 3]
The elegant way to totally separate the view model from the presentation layer would be to inject the command itself. Than the view model would not be aware of presentation layer. It would only execute the injected action - no matter what it is.
Question 1:
Which approach would be best? I guess the number 3 is the winner.
Question 2:
Should this even be a part of the view model? I think it shouldn't as it seems to be the concern of the presentation layer. Maybe it's best to put it in a simple event handler in code behind?
The second example is more complex. In the same control we have a "Delete" button. It should open a dialog asking user for confirmation and if he says 'yes' it should delete something. In this case it makes more sense to put it in the view model as it really affects the data.
Question 3
This case is the most tricky for me. I can't use my favorite approach number 3, because I have to display a dialog which is a presentation layer's job, but also I have to perform some logic depending the dialog's result - which on the other hand is view model's job. What is the best approach here?
Please bare in mind that I really don't want to use approaches 1 and 2. I want the view model to be clean and unaware of anything related to the presentation layer - not even by weak references.
One thing that comes to my mind it to split the view model layer into two layers. Something like:
view --> presentation view model --> logic view model
presentation view model
used as a control's context
contains logic view model as a public property for direct bindings
uses approach number 2 - now it's acceptable as the whole class is meant to perform presentation related actions
logic view model
it is 'presentation free'
references specialized logic services
some commands could be bound directly to the view
some commands could be executed by the presentation view model which owns it
Maybe this is the right way to go?
[EDIT]
In response to the suggestions in comments about using a framework:
Using a framework will surely make it easier to handle windows, but it's not the solution to the problem. I don't want the 'logic view model' to handle windows at all, not even with a help of a framework. Referring to the approach I suggested at the end I would still put it in the 'presentation view model'
Your ViewModel should just notify all the subscribers that the command was executed by firing a simple event. The View should subscribe to that event and handle the event by displaying a new Window...
ViewModel:
public event EventHandler<NotificationEventArgs<string>> DisplayDetailsNotice;
private DelegateCommand displayDetailsCommand;
public DelegateCommand DisplayDetailsCommand
{
get { return displayDetailsCommand ?? (displayDetailsCommand = new DelegateCommand(DisplayDetails)); }
}
public void DisplayDetailsWindow()
{
//
Notify(DisplayDetailsNotice, new NotificationEventArgs<string("DisplayDetails"));
}
View (note that the VM is already the DataContext of the View):
private readonly MyViewModel mvm;
//Get reference to VM and subscribe to VM event(s) in Constructor
mvm = DataContext as MyViewModel;
if (mvm == null) return;
mvm.DisplayDetailsNotice += DisplayDetails;
private void DisplayDetails(object sender, NotificationEventArgs<string> e)
{
DetailsWindow = new DetailsWindow { Owner = this };
DetailsWindow.ShowDialog();
}
This way, when the command is executed the VM raises the event and the View which is subscribed to VM events handles the event by displaying the details windows using the ShowDialog() method. Since all the VM does is publish an event it remains agnostic of and decoupled from the View leaving the MVVM pattern intact. Since VM is already the DataContext of the View and the View binds to properties of the VM as it is obtaining a reference to the VM is also not breaking the MVVM pattern...
Note that this syntax is valid with Simple MVVM Toolkit MVVM framework. As suggested in comments you should start using an MVVM framework (my recommendations are Simple MVVM Toolkit or MVVM Light, Caliburn is too complex for no reason and no gain IMO) in order to avoid having to deal with the plumbing yourself...
I am using MVVM Foundation but I think its quite straight-forward and not really framework specific. My setup is as follows:
StartViewModel - has a ExitCommand that returns a RelayCommand/ICommand
public ICommand ExitCommand {
get { return _exitCommand ?? (_exitCommand = new RelayCommand(() => MessageBox.Show("Hello World"))); }
}
public RelayCommand _exitCommand;
StartView (User Control) has a button binded to the ExitCommand
<Button Content="Exit" Command="{Binding ExitCommand}" />
First, read as much as you can stomach on MVVM, e.g. WPF Apps With The Model-View-ViewModel Design Pattern on MSDN. Once you understand the basic principles driving it the answer will seem more reasonable.
Basically you want to keep your View (UI) and ViewModel (essentially abstract UI, but also abstract Model) layers separate and decoupled. Showing a message box or closing a window should be considered a UI specific detail and therefore implemented in the View, or in the case of a message box, more generally available via a 'Service'.
With respect to the ViewModel, this is achieved using Inversion of Control (IoC). Take the message box example above. Rather than showing the message box itself, it takes a dependency on an IMessageBoxService which has a Show method and the ViewModel calls that instead - delegating responsibility. This could be taken further by leveraging Dependency Injection (DI) containers.
Another approach used for closing a View window might be for the ViewModel to expose an event, called for example RequestClose (as in the MSDN article), that the View subscribes to. Then the ViewModel would raise the event when it wants the corresponding View / window to close; it assumes something else is listening and will take responsibility and actually do it.
you can implement an CloseEvent in your StartViewModel. in your StartView you have to register this CloseEvent. when you Raise your closeevent from your VM then, your View recognize that it has to close your app/window.
I've been doing the best I can to try to stay true to the separation recommended by the MVVM pattern. One thing I haven't figure out how to do correctly has to do with initializing my UserControls.
My most recent example of this has to do with a library that I wrote to talk to some low-level hardware. That assembly happens to have a UserControl that I can simply drop into any GUI that uses this hardware. All that is necessary for it to work is to set a reference to the object that has access to the low level methods.
However, that's where my problem lies -- currently, the UserControl is added to the GUI via XAML, where I define the namespace and then add the UserControl to my window. Of course, I have no control over its creation at this point, so the default constructor gets called. The only way to set the necessary reference for hardware control involves calling a method in the UC to do so. The ViewModel could feasibly call a method in the Model, e.g. GetController(), and then call the method in the UserControl to set the reference accordingly. The GUI can pass a reference to the UserControl to the ViewModel when said GUI creates the ViewModel, but this violates MVVM because the ViewModel shouldn't know anything about this control.
Another way I could deal with this is to not create the UserControl in XAML, but instead do it all from code-behind. After the ViewModel gets initialized and retrieves an initialized UserControl (i.e. one that has the low-level object reference set), it can set the Content of my Window to the UserControl. However, this also violates MVVM -- is there a way to databind the Content of a Window, TabControl, or any other element to a UserControl?
I'd like to hear if anyone has had to deal with this before, and if they approached it the first or second way I have outlined here, or if they took a completely different approach. If what I have asked here is unclear, please let me know and I'll do my best to update it with more information, diagrams, etc.
UPDATE
Thanks for the responses, guys, but I must not have explained the problem very well. I already use RelayCommands within the UserControl's ViewModel to handle all of the calls to the hardware layer (Model) when the user clicks in the control in the UserControl itself. My problem is related to initially passing a reference to the UserControl so it can talk to the hardware layer.
If I create the UserControl directly in XAML, then I can't pass it this reference via a constructor because I can only use the default constructor. The solution I have in place right now does not look MVVM-compliant -- I had to name the UserControl in XAML, and then in the code-behind (i.e. for the View), I have to call a method that I had added to be able to set this reference. For example, I have a GUI UserControl that contains the diagnostics UserControl for my hardware:
partial class GUI : UserControl
{
private MainViewModel ViewModel { get; set; }
public GUI( Model.MainModel model)
{
InitializeComponent();
ViewModel = new MainViewModel( model, this.Dispatcher);
ViewModel.Initialize();
this.DataContext = ViewModel;
diagnostics_toolbar.SetViewModel( ViewModel);
user_control_in_xaml.SetHardwareConnection( model.Connection);
}
}
where the outer class is the main GUI UserControl, and user_control_in_xaml is the UserControl I had to name in the GUI's XAML.
Looking at this again, I realize that it's probably okay to go with the naming approach because it's all used within the View itself. I'm not sure about passing the model information to user_control_in_xaml, because this means that a designer would have to know to call this method if he is to redo the GUI -- I thought the idea was to hide model details from the View layer, but I'm not sure how else to do this.
You will also notice that the main GUI is passed the Model in the constructor, which I assume is equally bad. Perhaps I need to revisit the design to see if it's possible to have the ViewModel create the Model, which is what I usually do, but in this case I can't remember why I had to create it outside of the GUI.
Am new to MVVM myself but here's a possible solution:
Create a property in your VM that is of the object type (that controls the hardware) and bind it to an attached property on your UserControl. Then you could set the property in your VM using dependency injection, so it would be set when the VM is created. The way I see it, the class that talks to the hardware (hardware controller) is a service. The service can be injected to your view model and bound to your UserControl. Am not sure if this is the best way to do it and if it is strict enough to all the MVVM principles but it seems like a possible solution.
if your question is: How do i show my viewmodel in the view? then my solution is always using viewmodelfirst approach and datatemplates.
so all you have to do is wire up your viewmodel via binding to a contentcontrol.content in xaml. wpf + datatemplates will do the work and instantiate your usercontrol for your viewmodel.
You are right, the ViewModel shouldn't know about anything in the View - or even that there is such a thing as a View, hence why MVVM rocks for unit testing too as the VM couldn't care less if it is exposing itself to a View or a test framework.
As far as I can see you might have to refactor things a little if you can. To stick to the MVVM pattern you could expose an ICommand, the ICommand calls an internal VM method that goes and gets the data (or whatever) from the Model, this method then updates an ObservableCollection property of the data objects for the View to bind to. So for example, in your VM you could have
private ICommand _getDataCommand;
public ICommand GetDataCommand
{
get
{
if (this._getDataCommand == null)
{
this._getDataCommand = new RelayCommand(param => this.GetMyData(), param => true);
}
return this._getDataCommand;
}
}
private void GetMyData{
//go and get data from Model and add to the MyControls collection
}
private ObservableCollection<MyUserControls> _uc;
public ObservableCollection<MyUserControls> MyControls
{
get
{
if (this._uc == null)
{
this._uc = new ObservableCollection<MyUserControls>();
}
return this._uc;
}
}
For the RelayCommand check out Josh Smiths MSDN article.
In the View you could either call the ICommand in the static constructor of your UC - I am guessing youwould need to add an event in your class for this - or call the ICommand from some sort of click event on your UC - maybe just have a 'load' button on the WPF window. And set the databinding of your UC to be the exposed observable collection of the VM.
If you can't change your UC at all then you could derive a new class from it and override certain behaviour.
Hope that helps a bit at least, like I say, have a look at Josh Smiths MVVM article as he covers the binding and ICommand stuff in there brilliantly.
If you set the DataContext of the Window or UserControl containing thisUserControl to the main view model, the user control can call SetHardwareConnection() on itself in its Loaded event (or DataContextChanged event handler).
If that's not possible because you're saying the UserControl is 'fixed', you should derive from it or wrap it up in another UserControl, which would serve as a MVVM 'adapter'.
(In order to bind the window: you could make the MainViewModel a singleton with a static Instance property and use DataContext="{x:Static MyClass.Instance}". A nice way to get things going quickly)
Note; this is based on my understanding that MVVM works because of Bindings.. I always bind the control to a ViewModel, not pass a ViewModel as a parameter.
Hope that helps!