I've been learning the MVVM pattern with Josh Smith's article and I want to create a classic layout with some links to the right (managed with commands) so when I click one I can show my view to the right into a tab control (inside it there is a ContentControl).
This is simple when I use a DataTemplate with the specific View and ViewModel I want to show on screen like this.
<!-- this section into my MainWindow's resources file -->
<DataTemplate xmlns:vm='clr-namespace:WpfFramework.ViewModels'
xmlns:vw='clr-namespace:WpfFramework.Views'
DataType="{x:Type vm:MySpecificViewModel }" >
<vw:MySpecificView />
</DataTemplate>
But, I want something more generic. I mean that my mainWindow should not know a specific View nor a specific ViewModel. It should only know that it binds to some commands and has a tab control which shows "some view". Every sample including Josh Smith's article seems to have limited universe of views and viewmodels, that's great with a sample.
So, how can I tell my ContentControl that some view (with its corresponding viewModel) is gonna be there without being so specific (without "burning" into the mainView the concrete types)?
best regards
Rodrigo
PD. I have tryed with base a ViewModel and Base View but it doesn't seem to work.
In your main View, bind a ContentControl to a generic ViewModelBase property
<ContentControl Content="{Binding CurrentPage}" />
CurrentPage would be defined in the main ViewModel as a ViewModelBase object, and to switch pages you simply set CurrentPage to whatever you want.
So when you click on something like the HomePageCommand, the main ViewModel would execute CurrentPage = new HomePageViewModel(); providing that HomePageViewModel inherits from ViewModelBase.
I wrote something a little while ago that shows some samples here if you're interested
Related
I am a newbie in WPF. I was exploring MVVM Pattern for WPF applications. I am having trouble in binding Text property of a TextBox from VIEW to a variable in VIEWMODEL
Here is the TextBox from MainWindow.xaml
<TextBox x:Name="UsernameTxt" Grid.Row="4" materialDesign:HintAssist.Hint="Username"/>
I just need to know how to bind its Text Property to ViewModel Class in Class Library
Thanks
I think it's possible to give a very generic answer to this very generic question.
If the question changes context this answer is very likely to be deleted but here goes anyhow.
You want your viewmodel to be in the datacontext of the textbox. Because datacontext is inherited down the visual tree this usually means you want to set datacontext of your window to an instance of the viewmodel. Or maybe the usercontrol your textbox is in, but we know nothing about your app so let's just cover the simple scenario.
Your options are to instantiate a viewmodel using code or xaml.
If you look at this article:
https://social.technet.microsoft.com/wiki/contents/articles/31915.wpf-mvvm-step-by-step-1.aspx
That instantiates in xaml.
Note the xmlns is
xmlns:local="clr-namespace:wpf_MVVM_Step01"
That's saying where you see some bit of markup which is prefaced "local:" then go get the class out of this namespace.
To point to a different dll ( a class library ) you need to tell it which assembly. You do that by adding ;assembly=Whicheverdll to your equivalent of that xmlns. And of course that won't be local then so give it a different name. You also need a reference to that dll or project added to the entry point exe.
Once you've done all that and your viewmodel is instantiated into memory and in the datacontext of that textbox you need some sort of binding.
Which the article covers but that will be something like:
<TextBox Text="{Binding YourPublicStringProperty}"/>
I am working on a an WPF MVVM application where I need to have a Main Window with just a logo and it has to show child views inside it. I don't have any controls in Main Window all the controls reside in child view for example Buttons like Next, Back, Cancel and some text blocks etc. Now If users select Next button on the child view I have to draw or load the next child view inside the Main Window. If Back button is clicked I have to go back to the previous child view. So basically I am changing the child views depending on which button is clicked. Also I am maintaining different view models for every child view. Now the problem is I am not able to figure how should I link the child views to there respective view models. This application is similar to some Installation applications where different dialogs are shown depending on the selection and the button clicked by the user.I am new to this wpf and don't want to use MVVM Light , Prism etc. Any detailed help will be greatly appreciated. Thanks in advance.
One of the easiest ways to associate any data type with XAML controls is to use a DataTemplate. Therefore, you can simply add something like this into your Application.Resources and as long as you do not set the x:Key properties on the DataTemplates, then they will be explicitly applied by the Framework whenever it comes across instances of your view models:
<DataTemplate DataType="{x:Type ViewModels:HomeViewModel}">
<Views:HomeView />
</DataTemplate>
...
<DataTemplate DataType="{x:Type ViewModels:MainViewModel}">
<Views:MainView />
</DataTemplate>
Then displaying the view is as simple as this:
<ContentControl Content="{Binding YourViewModelProperty"} />
In code behind, or your view model:
YourViewModelProperty = new MainViewModel();
It's often handy to create a base class for your view models and then the YourViewModelProperty can of that type and you will be able to interchange them using the same property and ContentControl.
UPDATE >>>
The general idea is that you have one MainViewModel class with one BaseViewModel property data bound to one ContentControl in MainWindow.xaml... the navigation controls should also be in MainWindow.xaml and not in the views themselves. In this way, the MainViewModel class is responsible for changing the property to the relevant view model instances when it receives navigation Commands from the MainWindow.xaml.
I made a UserControl with the MVVM pattern, where the UserControl's "intelligence" is in its viewModel.
I want to user that UserControl in different views (xaml) so the developer of that view doesn't have to mind about how it is done.
I added some dependencyProperties in my UserControl so the end-programmer could give the control some context informations.
But I have some binding issues.
In the client.xaml:
<Grid>
<MyUserControl MyDependencyProperty0={Binding ClientViewModelProperty0}/>
</Grid>
and in myusercontrol.xaml
<Grid>
<TextBlock Text={Binding TextToDisplay}/>
</Grid>
where TextToDisplay is a property of MyUserControlViewModel.
I only need the ClientViewModelProperty0 to be set once, I do not need the clientViewModel to be set as the DataContext of MyUserControl since it has its own dataContext(its view-model)
I assume the solution would be a different Binding Expression syntax (relative source? self?) but I cannot see which one...
Reusable controls tend to follow a somewhat different design than full-blown application views. Specifically, they don't follow MVVM in quite the same way.
Remember that in WPF, controls are "lookless": their visual appearance is governed by templates. The underlying class is the "model" for the control. Like #Will mentioned in his comment, a TextBox does not have a TextBoxViewModel; the TextBox instance is the "view model". The "view" is the template that gets applied. While a UserControl is a bit different from a templated control (its content is self-contained, so it's effectively both the "view" and the "view model"), the same basic rules apply:
When you create your own reusable controls, put your properties and behavior in the control class itself. That way, when you plug it in to a view, you can set the parameters however you like, e.g., by binding them against the parent view model. A reusable control should never rely on some external/ambient view model being present.
Our application is a large project with many modules and view. The main window has a ribbon in it, and we are looking for the best way to integrate the ribbon in the application.
I've created a service which modules a views can register to add ribbon items relevant for them, and, in addition, any main view instance can provide its own ribbon items relevant to the that instance. a RibbonItem is a small class which abstract the options of a ribbon item, and mainly have Title, Description, Command, UIType and ChildItems. The service is in charge to rebuild the ribbon when the main view changes.
A colleague of mine thinks this is bad MVVM, as users need to design their ribbon view in C# code and not in XAML, and he also say it would be hard in this way to make a group of items disabled or enabled at once, as each command of these items will need to update its CanExecute separately. Instead, he suggested to have a main Ribbon View and ViewModel files, where each developer that want to add a ribbon button for her module or view would need to add them in the View XAML and add a relevant command in the ViewModel. In addition, VisualStates will be used to determine what items will be displayed or enabled based on changes in the ViewModel (such as view change, or selection change). I really don't like this solution, mainly because all developers will have to put their modules knowledge in once big file.
Note that some items in the ribbon (e.g. Options, Exit) are common to the entire application, while some are relevant to a specific application domain and some are only relevant for a specific view.
Edit: I guess my main question is what is the recommended way to allow multiple development teams integrate on a single ribbon? Should we have a single RibbonView and single RibbonViewModel which will contain all of the possible items in a ribbon, and each team will add its items to these V/VM and also define the logic on when to show them (probably by using visual state)? Or do we allow every view, view-model or module register ribbon items (within their own C# code) against a service, and have the service then render the ribbon as needed when the active view changes with all items registered to that type? Or is there any better way to achieve this integration?
What do you think?
Do you have a better idea or an opinion about how to manage the single ribbon resource which is common to multiple developers?
Thanks,
splintor
I agree with Will's comment, your viewmodel should not care or know how it is being rendered or if the designers ever decide to change how it's rendered.
A ViewModel should only contain all required information for the presentation layer to render it.
So the ViewModel should have all the properties that the Ribbon bar needs bind to in order to function. Then you can use a Resources.xaml or some other strategy to present it.
Taking a shot in the dark I would try something like this for the ViewModels:
public interface IMenuViewModel : INotifyPropertyChanged
{
ICommand Command {get;}
string Title {get;}
string Description {get;}
UIType Type {get;}
IList<IMenuViewModel> ChildItems {get;}
}
I would then probably create an abstract class that provides implements INotifyPropertyChanged with a collection class the implements INotifyCollectionChanged to take care of the plumbing code.
I would then probably do something like this in the Resources.xaml
<DataTemplate DataType="{x:Type vm:IMenuViewModel}">
<StackPanel>
<Button Command="{Binding Command}" Content="{Binding Type}"/>
<ItemsControl ItemsSource="{Binding ChildItems}"/>
</StackPanel>
</DataTemplate>
to provide a default view for your viewmodels
and then all someone has to do to create an entry into your ribbon bar is
1) Implement IMenuViewModel
2) Optionally add another DataTemplate entry into your resources.xaml if they want their widget rendered differently like so:
<DataTemplate DataType="{x:Type vm:FooViewModel}">
<v:FooView />
</DataTemplate>
I hope I didn't dig to deep on how I would implement.
The main point is that a ViewModel should only expose properties required for the view to do it's job(which is rendering the ViewModel), not for the ViewModel to do the job or care how it's done.
I'm doing some research on WPF and MVVM to evaluate if this is something we wish to implement in a project.
There is one particular thing that I quite cannot understand (my book on WPF hasn't arrived yet).
I've read Josh Smith's article 'WPF Apps With The Model-View-ViewModel Design Pattern' and also his article 'Using RoutedCommands with a ViewModel in WPF'.
My demo application is somewhat different from Josh Smith's demo in that I have menu items that aren't directly bound to the main view model, but would rather be handled by other view-models.
My main window is bound to a MainViewModel object which exposes a object called View (derived from a ViewModelBase class and bound to the Main Window through a ContentControl). This View object is replaced with different ViewModel's such as CustomerViewModel, CustomersViewModel etc. (these are rendered using views defined in my resource dictionary: ).
All this is well and find, but since I wan't menu items in my main window (such as New, Save etc.) that should be enabled, disabled based on the view I found Josh Smith's article on the CommandSink pattern(?) but he states that it is obsolete, and one should rather use the RelayCommand.
Now I am confused, as I cannot figure out how to implement this functionality using this approach.
Thanks,
Vincent
A simple way to do this is to have each view expose a property of type MenuItem, which contains its local menu. (The menu itself can live in the view's resource dictionary; you just implement a property getter that retrieves it using FindResource.)
Then make your main menu look something like this:
<Menu>
<MenuItem Header="File">
<!-- content for your application's File menu goes here -->
</MenuItem>
<MenuItem Header="Edit">
<!-- content for your application's Edit menu goes here -->
</MenuItem>
<MenuItem Header="{Binding SelectedView.MenuItem.Header}"
ItemsSource={Binding SelectedView.MenuItem.Items}/>
<MenuItem Header="Help">
<!-- content for your application's Help menu goes here -->
</MenuItem>
</Menu>
Edit
I think I misunderstood your question, but in part that's because I think your question's much easier to answer than the one I thought you were asking.
Create a RoutedCommand property in your application view model called DisabledCommand that is always disabled. Then bind your application menus to commands like this:
public RoutedCommand SaveCustomerCommand
{
get
{
CustomerView cv = SelectedView as CustomerView;
return cv == null
? DisabledCommand;
: ((CustomerViewModel)cv.DataContext).SaveCommand;
}
}
The casting is a little awkward looking, but other than that this is straightforward, elegant even. The only implementation detail your application view needs to know about the customer view is that there's a SaveCommand on its view model.