I have a functional MVVM patterned SL app with a RadWindow (essentially a ChildWindow), that I would like to remove the code-behind in my view that shows the window using its ShowDialog. Both the main view and the window is bound to the same ViewModel if that helps.
The button has both a ViewModel command using a MVVMLight RelayCommand to handle setting state as well as the event handler in the View.
The ultimate solution/pattern will be reused 20+ times so something better than code-behind would be great.
Thoughts?
private void Button_Click(object sender, System.Windows.RoutedEventArgs e)
{
var window = new RadWindowTest.Controls.ChildWindow1();
window.Closed += new System.EventHandler<Telerik.Windows.Controls.WindowClosedEventArgs>(window_Closed);
window.ShowDialog();
}
In this case I would suggest you implement DialogService. This service you can inject into your view model, for testing you will have to inject an instance that does not depend on the view, thus maintaining testability. You can use the ViewModelLocator to make this service available to your application.
Another approach would be to implement a ViewBase class that implements an interface that allows you to display the dialog. This interface is now used by the ViewModel to display a dialog. Again to test you need to provide a different implementation of the interface. A sample can be found here.
Both ideas revolve around the same concept of factoring out the function that shows the dialog. In order to strictly de-couple the View and the ViewModel you will have to think about how the ViewModel specifies which dialog has to be shoen, and how the dialog resut or dialog model is returned to the calling ViewModel.
Which approach is better is open to your judgement. Personally I prefer the first approach as I do not have to inherit the views from a common base class.
PS: Use a command to get to the point in your ViewModel where you want to show the dialog. Using a dialog service should need no code behind.
Related
I don't know C# events very well so I have difficulties in understanding some code I found in internet
Inside the code behind of a view file there is the following method:
public void SavingMesBoxClosedHandler(object sender, object args)
The DisplayMessageBox class is derived form FrameworkElement and defines the following event:
public delegate void MessageBoxClosedHandler(object sender, object args);
public event MessageBoxClosedHandler DialogClosed;
Inside the xaml of the view:
<DisplayMessageBoxDemo:DisplayMessageBox
// some dependency properties here
DialogClosed="SavingMesBoxClosedHandler"/>
I thought I could use only dependency properties, while DialogClosed is an event.
Which is the magic to map a method of the view to an event in DisplayMessageBox class using only its name ?
Why don't I have to use a binding ?
Is there an easy way to assign a viewmodel method as the event handler of DialogClose ?
May be I didn't use the correct terms in my last question. To put in other words I want to call a method inside my viewmodel, not in the view as in the example I reported above.
You don't have to use only dependency properties in XAML. You can use normal properties just as well. Dependency properties are a necessity when you use DataBinding, as you point out. In the case you mention there seems to be no need to use DataBinding because you will not use different handlers depending on your DataContext. If you want to stick to the MVVM pattern and keep the event handling logic in your view model, you can use EventTrigger: http://www.kunal-chowdhury.com/2010/11/using-eventtrigger-in-xaml-for-mvvm-no.html
I'm trying the MVVM pattern and I've run into a problem.
Here's how I instantiate my model:
<common:LayoutAwarePage
...
...(omitted boiler plate generated lines here)
...
...
mc:Ignorable="d">
<common:LayoutAwarePage.DataContext>
<local:TextGameClientModel x:Name="textGameClientModel"/>
</common:LayoutAwarePage.DataContext>
But when I try to use it, I get a NullReferenceException because this.textGameClientModel is NULL:
public MainPage()
{
this.InitializeComponent();
this.textGameClientModel.runsPublished += textGameClientModel_runsPublished;
}
I've also tried the same line in the Page's OnNavigateTo handler, and also in the OnLoaded handler, but with the same result.
Where is the right place to hook up my event handler?
(Please don't let my code-behind in an MVVM project distract you from the question. My use of a RichTextBox has forced me to color outside the lines a little.)
I actually wrote an answer about the WPF Creation Steps fairly recently, however that's not the problem in this case.
In this case, you are setting the DataContext in your XAML, however that's not the same as setting the textGameClientModel property
You need to do something like this to set the property equal to your DataContext first
this.textGameClientModel = this.DataContext as GameClientModel;
or simply cast your DataContext as your class to setup the event
((GameClientModel)this.DataContext).runsPublished += textGameClientModel_runsPublished;
As a side note, I never recommend hardcoding the DataContext into a UserControl like you have. By doing so, you are preventing any other DataContext from getting passed to the UserControl, which kind of defeats one of the biggest advantages of WPF/MVVM, which is having separate UI and data layers.
I'm new to Silverlight/MVVM. I tried some example of MVVM Light, it looks great.
For my scenario, I want to create a Panorama Page, for each Panorama Item, showing my usercontrol, a item list for a customer.
I've built usercontrol(view), viewmodel and WCF service model and works well in a single Panorama Item(Only use first customer).
Also, I use Locator of MVVM Light shown in MIX10 demo, it enables me to make design time data for Expression Blend.
My viewmodel will receive a parameter of customer ID then exchange data with WCF based on this ID.
And the customer list also comes from WCF. So I can't actually makes viewmodels in Locator's static constructor.
If viewmodels are built in runtime by calling Locator, how to make data binding?
The only way I think about is to make viewmodel object in usercontrol's constructor and make it datacontext.
Is there a better solution?
If you want to keep the same declarative model in the XAML, you can put a CurrentCustomerViewModel property on the locator and then set property to the right viewmodel before you navigate to the page.
Personally though for pages like that I typically put a viewmodel factory method on the locator (so it can cache them, etc) and call it from the OnNavigatedTo method, something like this.
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
string id = NavigationContext.QueryString["customerID"];
vm = ViewModelLocator.GetCustomerViewModel(id);
DataContext = vm;
base.OnNavigatedTo(e);
}
Then I just use Blend's sample data capabilities for design time data. This way also helps support pinning the page to the start screen since that will be the entry point to the app and I won't necessarily get a good chance to set the "CurrentCustomerVM" property anyway.
I have a usercontrol that i want to use throughout my Silverlight MEF MVVM solution.
I want to be able to link it up with one of a number of ViewModels depending on which module i am in. What this control does is list the records of a given entity so i can Add, Edit or Delete. I realized i would be using this control in multiple locations - to update several lookup tables, so i decided to make it's ViewModel dynamic. As seen below, I am using the Galasoft MVVM plugin.
if (!GalaSoft.MvvmLight.ViewModelBase.IsInDesignModeStatic)
{
// set DataContext
DataContext = PluginCatalogService.Instance.FindSharedPlugin(ViewModelTypes.ViewModelMT, PluginType.ViewModel);
_viewModel = (ViewModelMT)DataContext;
}
My question is how can i dynamically change from ViewModelMT to ViewModelCT to allow me to independently display lookup tables e.g. Maintenance Types and Contract Types on an instance of this same usercontrol? I took a look at the Viewmodel locator, but I'm still not sure how to get this done.
Thank you
I don't think this is really a ViewModel thing. It's more of a Service problem.
Your ViewModel for the control will not change but you'll dynamically slot in the required service to maintain your list. ie. MaintenanceTypeService and ContractTypesService will implement IListMaintenanceService which exposes an list of items and Add,Delete and Edit commands.
I want to navigate from a login screen to the dashboard in my Silverlight OOB app.
I started using Caliburn.Micro but now I'm having doubts seeing as all I can use is the Conductor. Or am I missing something?
Note: I changed constructor to Conductor as originally intended. This is what you get for not proofreading your questions.
There are several ways you could display a login screen, probably the nicest is to initiate it from your ShellViewModel. So, your ShellViewModel would have a dependency on your LoginViewModel, which you could inject as an abstraction (ILoginViewModel), or better still use an abstract factory instead, and inject that into your ShellViewModel constructor.
Either way, once you have an instance of your LoginViewModel in the ShellViewModel, you can display it either as a modal dialog box (in which case use the Caliburn.Micro WindowManager.ShowDialog method - inject this dependency as an IWindowManager abstraction), or display the login view as part of your shell views main content area, in which case your ShellViewModel would be a conductor, and will activate an instance of your LoginViewModel with the ActivateItem method.
Once you have received input from your LoginViewModel, either as a modal dialog or conducted view, you can display your DashboardViewModel as appropriate using the ShellViewModel as a conductor.