I have the following code in my C# WPF MVVM application.
public RelayCommand PolishCommand
{
get
{
polishcommand = new RelayCommand(e =>
{
PolishedWeightCalculatorViewModel model = new PolishedWeightCalculatorViewModel(outcomeIndex, OutcomeSelectedItem.RoughCarats);
PolishedWeightCalculatorView polish = new PolishedWeightCalculatorView(model);
bool? result = polish.ShowDialog();
if (result.HasValue)
{
But i came to know that, calling a window from viewmodel is wrong one in MVVM pattern.
Also stated in the below link.
M-V-VM Design Question. Calling View from ViewModel
Please help me anybody by providing an alternate solution.
Thanks in advance.
You are right that generally you should never access views from view models. Instead in WPF, we set the DataContext property of the view to be an instance of the relating view model. There are a number of ways to do that. The simplest but least correct is to create a new WPF project and put this into the constructor of MainWindow.xaml.cs:
DataContext = this;
In this instance the 'view model' would actually be the code behind for the MainWindow 'view'... but then the view and view model are tied together and this is what we try to avoid by using MVVM.
A better way is to set the relationship in a DataTemplate in the Resources section (I prefer to use App.Resources in App.xaml:
<DataTemplate DataType="{x:Type ViewModels:YourViewModel}">
<Views:YourView />
</DataTemplate>
Now wherever you 'display' a view model in the UI, the relating view will automatically be shown instead.
<ContentControl Content="{Binding ViewModel}" />
A third way is to create an instance of the view model in the Resources section like so:
<Window.Resources>
<ViewModels:YourViewModel x:Key="ViewModel" />
</Window.Resources>
You can then refer to it like so:
<ContentControl Content="{Binding Source={StaticResource ViewModel}}" />
I have answered a very similar question previously, which details how you can open a new window from your view model, whilst maintaining the separation of concerns that the MVVM pattern promotes. I hope this helps: Open a new Window in MVVM
You are allowed to break the rule. You don't have to follow MVVM completely.
I am always using commands to create a new view. You could even create an event (Amagosh, did he just say that!?) for when you click on a button.
I mean, this is just my opinion, I guess it depends on the style programming you're into.
Related
I'm trying to set a new DataTemplate as a new Window resource in my MainWindow derived from the System.Windows.Window class. The code for the XAML is quite simple and looks like this:
<Window.Resources>
<DataTemplate DataType="{x:Type model:MyViewModel}">
<view:MyView />
</DataTemplate>
</Window.Resources>
What I exactly do here?
I try to show my data (MyViewModel) in or as a specific view (MyView). So far I do understand. Otherwise I wouldn't see the form itself, but the view model as a string with my.namespace.MyViewModel in the window.
But programmatically I do not understand, how to achieve the same. I know, that I have to add a new DataTemplate to the resources of my window. For this I have to "tell" the DataTemplate, which view to use (for the representation) and which data I want to represent, right?
So it must be something with:
DataTemplate template = new DataTemplate();
template.DataType = typeof(MyViewModel);
// Something, something ...
this.Resources.add(...);
Is this the right way to go? Or am I completely wrong?
I searched the web for solutions and also my WPF book, but there are only XAML implementations.
Why do I do that?
I have a headered content control which loads view models dynamically. The problem here is, that the user controls are sometimes dynamic and in case of data presentation I need to assign a specific (dynamic created) view to the data. So I try to load the current static user controls also in the way shown above.
Is there a way to go?
Or is there a better way to achieve the same results?
Suppose I have two Pages in WPF namely Page1.xaml and Page2.xaml. I have one viewmodel named PageViewModel.cs. Both of those pages share the same viewmodel.
I can write my code by two methods:
Mehod1:
PageViewModel.cs
public static class PageViewModel
{
}
Page1.xaml
<Window.........>
<Window.DataContext>
<vm:PageViewModel />
</Window.DataContext>
</Window>
Page2.xaml
<Window.........>
<Window.DataContext>
<vm:PageViewModel />
</Window.DataContext>
</Window>
App.xaml
Default xaml code.
Method2:
PageViewModel.cs
public class PageViewModel
{
}
Page1.xaml
<Window DataContext={StaticResource PageViewModel}>
..........
..........
</Window>
Page2.xaml
<Window DataContext={StaticResource PageViewModel}>
..........
..........
</Window>
App.xaml
<vm:PageViewModel x:Key="PageViewModel" />
Can anybody explain the difference between above mentioned two methods?
The primary difference will be that in your first example, any object or method can access your view model, its data, and its methods.
In the second, you have an actual instance (albeit contained in a globally accessible object), so while other objects could still get to it, its not as easy as "access the static (read, global) instance".
Both have the same effect, you get data shared between the two views.
One additional option you may want to consider would be to pass the view model in on the constructor of the view. You have to use the code-behind, but you can give both view's a reference to the same view model object without having any global variables.
If these are subviews, then you could do the following:
MainView.xaml.cs
public void MainView()
{
SubViewModel subVm = new SubViewModel();
//If you are instantiating your views
MySubView view1 = new MySubView(subVm);
MySecondSubView view2 = new MySecondSubView(view2);
//Otherwise
view1.DataContext = subVm;
view2.DataContext = subVm;
}
In the spirit of the locator pattern, you could also simply bind the DataContext property of the sub views to a SubViewModel property on your main View Model.
The one thing to be aware of with this is that the View Model's lifetime will end once both sub views are destroyed. If you need a longer lifetime, then you should use the latter option and point it towards a long-lived object.
In general, I would stay away from static classes. They make unit testing, and good design in general, much more difficult to achieve. If you need a singleton, at least implement one properly as opposed to just using a static class.
This won't answer your question, BradleyDotNET has done that, but I just can't help my self here.
This is a perfect example for using a ViewModelLocator, try to install a framework such as GalaSoft MVVM Light. You may use your Locator to keep track of your viewmodels, static viewmodels are bad pie(you are going to run into alot of problems you can avoid).
I can't see where you have declared your static resource, but I assume it is in App.xaml ?
Check this post for using a viewmodel locator, don't be alarmed by the IOC stuff :). This is really handy and a great way to solve your issue.
Binding to someviewmodel, assuming the vmlocator is defined in App.xaml and that SomeViewModel is present there.
DataContext="{Binding Source={StaticResource ViewModelLocator}, Path=SomeViewModel}"
Hope it helps,
Cheers Stian
I am new to MVVM and working on an application, i want to achieve few things in my application
My viewmodel should be able to initiate a new view.
scenario(a command is bind to a button and some process decide what to do and based on the result, i need to show View1 or View2)
Upon a successfull operation my viewmodel should display a messagebox, if multiple views are open then message must prompt upon the right view(with which viewmodel is bind).
I want to provide some kind of notification from my view model to view. Kindly guide me in the right direction.
Thanks
You might want to try out some of the many mvvm frameworks out there. I personally like mvvm light because it works in silverlight and WPF, and it's easy to use http://mvvmlight.codeplex.com/ (no affiliation)
Here is a nice compare/contrast of some of the major frameworks: What framework for MVVM should I use?
Most of the frameworks have a messaging system that provides the ability to send updates between the view and the viewmodel as well as between viewmodels. Most of the frameworks also provide canned messages that handle MVVM messageboxs as well (I know MVVM Light does).
To handle switching between views in WPF I use DataTemplates and Content controls
In the view .xaml I add
<ContentControl Content="{Binding ActiveViewModel}" />
and this is the space where the injected view will be displayed. The ActiveViewModel is the object for the viewModel that holds the selected viewModel.
In a ResourceDictionary I add something like:
<DataTemplate DataType="{x:Type ViewModelNameSpace:ViewModelClassName}">
<ViewNameSpace:ViewClasName/>
</DataTemplate>
Finally in the ViewModel I set the ActiveViewModel property (that is setup to notify the UI of changes via INotifyPropertyChanged) to an instance of the viewModel I would like to use.
ActiveViewModel = new ViewModelClass();
You should create a new View and Navigate to it.
You can use messaging in MVVM Light framework. Send message from your ViewModel to View. Examples:
http://chriskoenig.net/2010/07/05/mvvm-light-messaging/
This is a question that extends from the originally posted here:
Link to loading-xaml through runtime
I'm working on a WPF MVVM application that loads XAML content dynamically from an external source, very similar as the answer in the post above.
Here is what I got so far:
My View declares an instance of the ViewModel as a resource and creates an instance of that ViewModel
In my ViewModel constructor I'm loading a XamlString property coming from an external source (file or db..)
In my view I have a button that user clicks after ViewModel finishes loading and in the click-event code-behind I'm deserializing the dynamically loaded XAML and add it to my grid.
My question is, how can I eliminate code-behind and automate the logic so the View can render the new xaml section dynamically right after the ViewModel is done getting the XAML content and initializing the string property?
Should I use some kind of Messaging Bus so the ViewModel notifies once the property has been set so the View can add the new content?
What troubles me is the fact that ViewModels do have a reference to Views and should not be in charge of generating UI elements.
Thanks in advance!
Edit:
Just to clarify: in my particular case I am not trying to bind a Business Object or Collection (Model) to a UI element (e.g. Grid) which obviously could be accomplished through templates and binding. My ViewModel is retrieving a whole XAML Form from an external source and setting it as a string property available to the View. My question is: Who should be in charge of deserializing this XAML string property into a UI element and add it programmatically to the my grid once my Xaml string property in the VM is set?
This sounds to me more of like a View responsibility, not ViewModel. But the pattern as i understand it enforces to replace any code-behind logic with V-VM bindings.
I have a working solution now and I'd like to share it. Unfortunately I did not get rid of code-behind completely but it works as I expect it to. Here is how it works(simplified):
I have my simplified ViewModel:
public class MyViewModel : ViewModelBase
{
//This property implements INPC and triggers notification on Set
public string XamlViewData {get;set;}
public ViewModel()
{
GetXamlFormData();
}
//Gets the XAML Form from an external source (e.g. Database, File System)
public void GetXamlFormData()
{
//Set the Xaml String property
XamlViewData = //Logic to get XAML string from external source
}
}
Now my View:
<UserControl.Resources>
<ViewModel:MyViewModel x:Key="Model"></ViewModel:MyViewModel>
</UserControl.Resources>
<Grid DataContext="{StaticResource Model}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<StackPanel>
<!-- This is the Grid used as a Place Holder to populate the dynamic content!-->
<Grid x:Name="content" Grid.Row="1" Margin="2"/>
<!-- Then create a Hidden TextBlock bound to my XamlString property. Right after binding happens I will trigger an event handled in the code-behind -->
<TextBlock Name="tb_XamlString" Text="{Binding Path=XamlViewData, Mode=TwoWay, UpdateSourceTrigger=LostFocus, NotifyOnValidationError=True, ValidatesOnDataErrors=True, ValidatesOnExceptions=True}" Visibility="Hidden" Loaded="tb_XamlString_Loaded" />
</StackPanel>
</Grid>
Basically I created a hidden TextBlock bound to my XAML String property in the ViewModel and I hooked its Loaded event to an event handler in the code behind of the View:
private void tb_XamlString_Loaded(object sender, RoutedEventArgs routedEventArgs)
{
//First get the ViewModel from DataContext
MyViewModel vm = content.DataContext as MyViewModel;
FrameworkElement rootObject = XamlReader.Parse(vm.XamlViewData) as FrameworkElement;
//Add the XAML portion to the Grid content to render the XAML form dynamically!
content.Children.Add(rootObject);
}
This may not be the most elegant but gets the job done. Like some people say, in MVVM there are some cases like this where little code-behind code is needed. It doesn't hurt and also part of this solution still uses the V-VM Binding principles when using the VM to retrieve and populate the XamlString property and exposing it to the View. If we would like to Unit Test the XAML parsing and loading functionality we could delegate it to a separate class.
I hope someone finds this useful!
I'm having trouble understanding what you're saying, so my answer will be based on my interpretation. You should consider posting a sample (simplified) of what you're trying to do.
1) I think you're misunderstanding what MVVM does. MVVM is mostly a binding-based pattern. Your view model should be exposing properties containing business objects and your view should just be binding to those properties. If I am misunderstanding you, and that's what you are doing, then your problem is that your view needs to be aware of when the properties get updated (after you deserialize your xaml, etc). There are two ways to do this: INotifyPropertyChanged interface on your viewmodel, or make your view model inherit from DependencyObject, and make the properties dependency properties. I won't go into details here, because this is a large subject that you should research on Google before making a decision.
2) Generally speaking, you shouldn't use click events inside your view if you're using MVVM. Instead, create properties on the view model of type ICommand (and create ICommand implementations to match, or use an implementation of DelegateCommand (google it) which will allow you to use delegates to implement the interface. The idea is, your view binds to the property and executes the handler directly inside the viewmodel.
3) If you want to push information from the viewmodel to the view, then you should create an event on the viewmodel and subscribe to it in the view, but this is a last resort, only to be used in cases like displaying a new window, etc. Generally, you should be using binding.
4) To be more specific about what you're doing, you should be binding your Grid's ItemsSource property to some property on the view model. Note, the property on the view model should be of type ObservableCollection<T> if you want to be able to add items and get instant updates.
Hope this helps.
My Main window defines the markup for the application, for this specific scenario lets say I have a grid with 2 columns.
First column will have navigation links, and second column will display the different views.
There are 2 views (and 2 viewmodels) defined in mainwindow xaml:
<Window.Resources>
<DataTemplate DataType="{x:Type vm:Window1ViewModel}">
<vw:Window1View/>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:Window2ViewModel}">
<vw:Window2View/>
</DataTemplate>
</Window.Resources>
And in second grid column that displays the views i got :
<ContentControl Content="{Binding Path=ViewModel}" HorizontalAlignment="Left">
</ContentControl>
Where ViewModel is a property that I set accordingly to a view(viewmodel) that i want to display.
Like :
ViewModel = new Window1ViewModel();
(datacontext of the mainwindowview is set to MainWindowViewModel)
So there is no problem to switch between views from the MainWindowViewModel.
My problem is how to switch within Window1ViewModel into Window1ViewMode2?
The various ViewModels don't "know" about other ViewModels.
Only MainWindowViewModel knos about others...
How can I solve this?
Maybe I should define a custom Event (with parameter), MainWindowViewModel will subscribe and other viewmodels will trigger it and then MainWindowViewModel will switch to the needed view?
the solution you describe is one possibility. One other I can think of is using some kind of Navigation-Service (static class or interface you pass to all your child-Viewmodels) that do this kind of work.
If your MainWindowViewModel creates all the others I would stick to the interface solution. You can for example let the MainWindowVM implement such a interface and inject it into all the child-vm on creation. This is much the same as your event-approach but instead of the childs-providing and the main having to subscribe you have the main give something ... IMHO the better approach.
Ok, may be I understood your point. You want that controller actually be modelview which notifies to mainmodelview about the fact that it have to be swapped with someone else.
Considering that we are talking about WPF, create DependecyProperty on mainmodelview , and set it from childview, which in code behind will trigger modelviews swap.