MVVM Displayer OberservableCollection<ViewModel> with unknown UserControl - c#

im a little bit stuck with my current project and hope someone can help me out of this.
My application works with plugins so that the user is able to add additional functionality to the application. Now i would like to have the configuration window in the same style (Maybe a plugin need some kind of configurations).
The configuration window loads all plugins and get the configuration ViewModel from the plugins. All the ViewModels are stored in an ObservableCollection. These ViewModels should be displayed in a TabControl (one tab per ViewModel)
But i dont know the type of UserControl the plugin is using, because the plugin come up with its own UserControl for configuration purposes.
Otherwise i would create a TabControl, bind its ItemsSource to the ObservableCollection and specify the UserControl in the Resources (DataTemplates).
But how to do it in case the UserControls are unknown to compile time?
I thought about using a ObservableCollection instead of ViewModels, but im not realy happy with that and even dont know if this will work.
Do you have some idea how to deal with that?
Kind regards,
SyLuS

You could use a ContentControl to achieve this.
It's used to show views depending on their viewmodel.
In your xaml you can specifiy which view should be shown. Based on the viewmodel which is the current DataContext.
<ContentControl>
<ContentControl.Resources>
<DataTemplate DataType="{x:Type vm:MyViewModel}">
<v:MyView/>
</DataTemplate>
</<ContentControl.Resources>
</ContentControl>
But when you say you are using a plugin system, maybe something like PRISM, you have to setup the datatemplates automatically. Never done this before. But maybe I gave you a point where you can start.

Related

Access DataContext of Page from MainWindow (with Telerik)

I am relatively new to WPF and I have stumbled across a problem that I just can't seem to find a solution for.
I am sure that there is already a thread concerning a problem like that but in regard of my lacking knowledge it is very likely that I haven't found it or simply did not understand it.
My problem:
I am developing a WPF-application in C#. It's an Outlook-Styled application with a big MainWindow with a huge ViewModel and XAML.
What I was trying to do, is to split up the single codefiles a bit to make it a little bit more modular and compact.
I am using Telerik Controls and tried to outsource the content of single SplitContainers into Pages, which worked fine until now.
Today, a new situation came up which is somehow stupid and wasn't looking too complicated, but somehow I can't get it to work.
Situation:
I have a Treeview in my "MainWindow" and whenever I change the selection in there, I want to change a property on my Page that I have made a binding to.
So, when I click on an item in "TreeView_3" I want to set a property via EventHandler (SelectionChanged_TreeView3) on the DataContext of "Page_X".
If I had to do this on the MainWindow, I would typically do it like that:
UserViewModel uvm = mainGrid.DataContext as UserViewModel;
Then just call whatever property of specific UserViewModel (ViewModel of the MainWindow) I want to access.
I can't do this the same the same way for the page obviously since "mainGrid.DataContext" will always refer to the MainWindow, since this is where the eventhandler is called.
So what I need would be a little explanation on how to access the DataContext from a page with a different ViewModel.
If you need any code in order to explain, let me know.
You need to separate your concerns. In your code behind your should have only code that handles view related stuff. Most often my codebehind is empty.
In your ViewModels you should handle your data related logic. So instead of casting the datacontext in your code behind, handle a click with a Commandin your viewmodel.
Since there is no possibility to bind a command to the SelectedItemChanged of your TreeView you can use an interaction trigger.
<TreeView xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectedItemChanged">
<i:InvokeCommandAction Command="{Binding Path=SomeCommand, Mode=OneWay}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TreeView>
Ruven it is hard to say without some example code. But it could be that you need to implement INotifyPropertyChanged on the ViewModels?
https://learn.microsoft.com/en-us/dotnet/framework/wpf/data/how-to-implement-property-change-notification
By calling OnPropertyChanged("PropertyName"); in the setter of a viewmodel property the ui will pick up the change.
Also make sure both views are referencing the same object and not copies of the same object.

UWP - How to show different View (UserControl) in each PivotItem when Pivot bound to list of ViewModels?

I'm building a UWP app using the Template10 Minimal template. I have a list of ViewModels that share a common base class. They are bound to a Pivot as follows:
ItemsSource="{Binding EnabledModels}"
I've setup multiple data templates to map each ViewModel concrete type to the View (UserControl) created for that particular ViewModel as follows:
<Pivot.Resources>
<DataTemplate x:Key="gettingStarted" x:DataType="vm:GettingStartedViewModel">
<v:GettingStartedPart DataContext="{Binding}"></v:GettingStartedPart>
</DataTemplate>
<DataTemplate x:Key="packageSelection" x:DataType="vm:PackageSelectionViewModel">
<v:PackageSelectionPart DataContext="{Binding}"></v:PackageSelectionPart>
</DataTemplate>
</Pivot.Resources>
I've not been able to determine how to get the View to actually display. Currently it will only display the type name of the ViewModel. I'm sure I've messed up the bindings somehow.
My ultimate goal is to present a Pivot with a series of data collection screens that all share a common base ViewModel, but each screen has it's own data needs. I'd like to keep the screens as separate UserControl views and dedicated ViewModels to make them easier to maintain independently.
I've looked for other patterns for multi-screen data capture in UWP that don't require separate pages but haven't had any luck.
Thanks for any guidance you can provide!
I was able to get the DataTemplateSelector to work so the Pivot would display a PivotItem containing the appropriate View (UserControl) for each ViewModel in my list of EnabledModels. Thank you to commenters Will and AVK Naidu.
Good resource for this situation available here

MVVM Light - Multiple ViewModels (and connecting them up)

I am trying to learn the MVVM pattern (C#), having come from a Windows Forms background. I am using the MVVM Light toolkit, and so far I think it is brilliant.
I have made several small applications, however one thing I am struggling with is introducing a second view.
I want to (for example), have a button on my MainViewModel, which via a RelayCommand, opens up a new Window - let's say an "About" window. I have done hours of research on the web for this however it seems I can't get my AboutViewModel to communicate with/show my AboutView.
I have placed a receiving messenger in the code-behind constructor of the AboutView.xaml - however I can't get it to receive any messages from the AboutViewModel, and thus can't make it 'Show()'.
If anyone has an example of an Mvvm Light WPF app using multiple views that would be great :)
There are two ways I can think to do this easily
The first would be to use a Popup instead of a new Window. For example, I often put properties in my ViewModel for PopupContent and IsPopupVisible, and set those values anytime I want to display my Popup control. For example, a ShowAboutPopup relay command might run something like this:
void ShowAboutPopup()
{
PopupContent = new AboutViewModel();
IsPopupVisible = true;
}
You can display it using a Popup object, or a custom UserControl. I prefer to use my own custom Popup UserControl, which will usually end up looking like this:
<Window>
<Canvas x:Name="RootPanel">
<SomePanel>
<!-- Regular content goes here -->
</SomePanel>
<local:PopupPanel Content="{Binding PopupContent}"
local:PopupPanel.IsPopupVisible="{Binding IsPopupVisible}"
local:PopupPanel.PopupParent="{Binding ElementName=RootPanel}" />
</Canvas>
</Window>
The PopupContent property is a ViewModel (such as an AboutViewModel), and DataTemplates are used to tell WPF to draw specific ViewModels with specific Views
<Window.Resources>
<DataTemplate DataType="{x:Type local:AboutViewModel}">
<local:AboutView />
</DataTemplate>
</Window.Resources>
The other method is to have some kind of ApplicationViewModel that runs on startup, and is responsible for the overall application state, which includes which window(s) are open.
Typically I prefer to have a single ApplicationView that contains a ContentControl to display the current page
<Window>
<ContentControl Content="{Binding CurrentViewModel}" />
</Window>
however it can also be used to manage multiple windows. If you do use it to manage multiple Window objects, be warned that this will not be a pure ViewModel because it will need to access some View-specific objects, and referencing UI objects it not something a ViewModel should do. For example, it may subscribe to receive ShowWindow messages, and upon receiving those messages it would create the specified View and show it, and possibly hide the current window as well.
Personally, I try to avoid multiple windows as much as possible. My usual method is to have a single View that contains consistent application objects for any page, and a ContentControl containing dynamic content that changes. I have an example using this navigation style on my blog if you're interested
As i can see you want a navigation in your MVVM app?
Word goes to the creator of MVVM Light - Laurent Bugnion - with his post about using Navigation Service for switching Views. It's actually about Windows Phone & Silverlight but same should apply to WPF.
Also this answer in related question uses this approach.

MVVM ViewModel to View Communication

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/

DataTemplate DataType, no class, just xaml

So I'm trying to understand some code we have on a project that is in C#/WPF. I'm pretty new and just learning whatever I can. Looking at one of the .xaml, we have a DataTemplate that lays out where things go for our app. I want to add some events to it, but there is no code behind the .xaml since it is not a class like other .xamls in our project. The DataType of the DataTemplate points to a ViewModel class, but this class does not see my objects in the DataTemplate. Any thoughts? Thanks.
To add rich event-based behavior to elements created through XAML, you need to utilize attached behaviors.
In addition to the attached behaviors John mentioned above, if you are using MVVM, you can utilize the commanding architecture in WPF. Check out ICommand and implementing those on your ViewModel. You will have something like this:
Command="{Binding YourCommandName}"

Categories