Same XAML but different code behind for user controls - c#

I have 3 user controls in WPF which have the same layout (a few buttons and a listview) but the code in behind is different because the listviews list collections of different classes.
Is it possible to somehow use the same XAML for the three usercontrols? Because right now, if I make a change to the layout of one XAML I have to do it for the other two manually.
Thanks

That's perfect scenario for MVVM
Create a single UserControl or View
Create three different backend classes which will act as ViewModel
For each instance of UserControl use different ViewModel as DataContext

1) Extract common XAML into the separate XAML file and then in target control's use it as DataTemplate:
<!-- 1. CommonView.xaml would contains common XAML -->
<!-- 2. Below is XAML of the any of three control -->
<UserControl>
<!-- In three controls use shared XAML as data template -->
<UserControl.Resources>
<DataTemplate x:Key="sharedTemplate">
<views:CommonView />
</DataTemplate>
</UserControl.Resources>
<MyControl>
<ContentPresenter ContentTemplate="{StaticResource sharedTemplate}" />
</MyControl>
</UserControl>
2) Bind each of the control to a separate ViewModel

Related

C# WPF - Switching between Grids

i am almost new to C# with WPF. I have a small problem. Maybe the solution is very easy, but i don't see it right now. So i want to make different TABLES. I use Grids to make my own table. Now i want to switch between the tables at different states of my application, so that i make a grid invisible and the one i need visible. How do i implement several grid tables in XAML? For example i have a tabcontrol and in the tabitem i want to place more than one grids, but thats not possible. I tried using StackPanel for example but then i have a gap at the bottom of the grid. I need a way to define several grids and switch between them. Before C# i worked with MATLAB and i just put every table in a PANEL and switched them visible and invisible when i needed them. Is there no similar way in WPF?
Greetings
In such cases, i would go with UserControls. One usercontrol for each grid type. A sample (not related to Grid in question) would be like the below.
<Window.Resources>
<ResourceDictionary>
<DataTemplate x:Key="DTGlobalAdminManager">
<AC:UCGlobalAdmin DataContext="{Binding Source={x:Static GVM:VMAdminConsole.Instance}, Path=ViewModelGlobalAdmin}"/>
</DataTemplate>
<DataTemplate x:Key="DTCompanyAdminProjects">
<AC:UCCompanyAdmin DataContext="{Binding Source={x:Static GVM:VMAdminConsole.Instance}, Path=ViewModelCompanyAdmin}" />
</DataTemplate>
<DataTemplate x:Key="DTProjectAdminManager">
<AC:UCProjectAdminManage DataContext="{Binding Source={x:Static GVM:VMAdminConsole.Instance}, Path=ViewModelProjectAdmin}"/>
</DataTemplate>
<DataTemplate x:Key="DTGlobalAdminAssignCategories">
<AC:UCGlobalAdminCategories DataContext="{Binding Source={x:Static GVM:VMAdminConsole.Instance}, Path=ViewModelGlobalAdmin}"/>
</DataTemplate>
</ResourceDictionary>
</Window.Resources>
You can set up a content control and different usercontrols (each containing different grid template). Then switch them using a Style Trigger.

Bind multiple views to multiple viewmodels

I have a WPF window displaying different self-defined Views. So far I was able to use everything I learned about MVVM :)
Now I got to a new "problem": I have 10 entities of the same view in a bigger view. These ten view-entities contain a set of controls (textbox, combobox etc.) but are all consistent.
So how do I bind these Views to a ViewModel?
I thought about having 10 instances of the ViewModel in the "higher-level" ViewModel and give the views fix-defined the instances of the VM as datacontext.
My question is now --> Is there a easier (or more convienient) way to bind many (identical) views to their viewmodels?
Code-Example:
View Model:
private PanelViewModel _panelViewModel1 = new PanelViewModel();
public PanelViewModel PanelVM1
{
get { return _panelViewModel1; }
}
View-Example:
<myControls:vwPanel HorizontalAlignment="Left" x:Name="vwPanel1"
VerticalAlignment="Top" DataContext="{Binding Path=PanelVM1}"/>
What bothers me is that I would need this logic ten times for ten views?
UPDATE:
To answer some questions: I want to show one view 10 times (in my example) I defined my own view by inheriting from UserControl. So my vwPanel inherits from UserControl. The 10 vwPanels are just placed inside a StackPanel inside a Grid.
It's not about displaying data, as you pointed out, there would be a listview or a datagrid a better place to start. It's a special case where I need this much input-controls :/
UPDATE2: What I hoped for was more like defining a List of ViewModels and Bind my 10 Views to one of this List. But this will not work will it? At least I wouldn't know how to refernce one "special" entitiy in the list out of XAML...
Typically I use implicit DataTemplates for mapping Views to ViewModels. They can go in <Application.Resources>, <Window.Resources> or even in under specific elements only such as <TabControl.Resources>
<DataTemplate DataType="{x:Type local:PanelViewModel}">
<myControls:vwPanel />
</DataTemplate>
This means that anytime WPF encounters an object in the VisualTree of type PanelViewModel, it will draw it using vwPanel
Objects typically get placed in the VisualTree through an ItemsSource property
<ItemsControl ItemsSource="{Binding CollectionOfAllPanels}" />
or by using a ContentControl
<ContentControl Content="{Binding PanelVM1}" />
If I understand your question correctly, you have a collection of something that you what to represent visually. That is, you have several viewmodels that you want to define a single view for, but show X number of times. Your example shows you using a panel as your view for the "PanelViewModel"...what is the parent item's control for the vwPanel? Assuming you're using something like a ListBox, you can define a custom DataTemplate that contains your vwPanel and assign that DataTemplate to your ListBox.ItemTemplate.
For example:
<Window.Resources>
<DataTemplate x:Key="myVMTemplate" TargetType="{x:Type myViewModels:PanelViewModel}">
<myControls:vwPanel HorizontalAlignment="Left" VerticalAlignment="Top"/>
</DataTemplate>
</Window.Resources>
<ListBox ItemsSource="{Binding Path=MyCollectionOfPanelVMs}"
ItemTemplate="{StaticResource myVMTemplate}" />
I haven't verified that this works.

How do I set view/view model data template at runtime?

This MVVM stuff is making my head hurt. I have an application which has a list of editors in a left pane. On the right is a tab control where the editors will be displayed. I have a main application view model that contains a collection of view models. I call this collection Workspaces. This is borrowed from the MvvmDemoApp that Microsoft provides here.
public ObservableCollection<WorkspaceViewModel> Workspaces
{
get
{
...
}
}
These workspaces are bound to a tab control in the main application window like so:
<DataTemplate x:Key "WorkspacesTemplate">
<TabControl
IsSynchonizedWithCurrentItem="True"
ItemSource="{Binding Workspaces}"
SelectedItem="{Binding ActiveWorkspace}"/>
</DataTemplate>
...
<ContentControl
Content="{Binding}"
ContentTemplate="{StaticResource WorkspacesTemplate}"/>
The view models are tied to a view using DataTemplates like so:
<DataTemplate DataType="{x:Type vm:MessageLogViewModel}">
<vw:MessageLogView/>
</DataTemplate>
This works fine. However, now I need to make the application configurable where the list of editors are read from a config file. I imagine this config file will contain the view and view model components for each editor. But, how do I tie the two together so that when someone binds to a view model (or a collection of view models), the correct view gets displayed (similar to what the DataTemplate does but in code, not XAML)?
I'm trying to stay away for Inversion of Control (IoC) techniques. I'm not sure our team is ready for that must sophistication.
IoC is the perfect solution for this however without this option you could creating the XAML data template in the view model using an XmlWriter and expose it as a property to bind to.
Edit: Bindings
You have your list of view models. Create and expose this XamlTemplate property in each view model (in a base view model class). The property should create Xaml along the lines of:
<DataTemplate xmlns:vw="...">
<vw:MessageLogView/>
</DataTemplate>
Then use a ContentControl to bind to:
<ContentControl Content="{Binding ViewModel}"
ContentTemplate="{Binding ViewModel.XamlTemplate}" />

How to define the usercontrols in mvvm pattern?

I using from mvvm in my application. I want know how to define my user control in mvvm pattern.
Must I define it by using from mvvm, or I can define it generally?
Let's just call the control that embeds the user control MainWindow, and the user control UserControl. Since you are in MVVM pattern, you have at least one View Model for the outer view - I usually use the name MainVm.
You have two choices for the user control: They can share the same View Model, or you could have a sub view model, just for the UserControl, i.e. UserVm.
For your first choice, you do nothing. You define UserControl (Visual Studio 'add new item' -> User Control is a pretty good start). Then, you simply embed it in Main Window.
<Window
x:Class="SO.MainWindow"
...
xmlns:src="clr-namespace:SO"
...
>
...
<src:UserControl />
...
</Window>
UserControl will inherit the same DataContext from MainWindow, and do all the {Binding} as you would do in the MainWindow.
If you want to have a sub view model (UserVm) - it would typically be a public property of the MainVm (say, userVm). In that case, you'll set the DataContext of the UserControl when you reference it.
<src:UserControl DataContext="{Binding Path=userVm}" />
Another popular paradigm would be to declare the DataTemplate instead of the UserControl. If you do that, you just need to put the UserVm (either instantiate it in the XAML, or through binding):
<Window x:Class="MainWindow" ...>
<Window.Resources>
<DataTemplate x:Key="UserDt"> <!-- or user TargetType instead of x:Key -->
...
</DataTemplate>
</Window.Resources>
...
<!-- You can put in a ContentControl like here: -->
<ContentControl Content="{Binding Path=userVm}"
ContentTemplate="{StaticResource UserDt}" />
<!-- or, if you defined TargetType for the DT, you can simply instantiate
the sub VM here. I don't like this apporach but it exists. -->
<src:UserVm />
</Window>
I think that depends on the user control. The user control can be just a view, in which case you would compose a larger control or page which has this user control as part of the whole. The larger control or page would provide the view and the view model parts for this view.
Or you could create a self contained user control which has all of mvvm and use events to interact with the larger user control that it is a part of.
I suspect you'll get better reuse and modularisation with the second approach.
In short: it depends.

Multiple grids in one area

I'm currently creating a WPF application, using C# and XAML in Visual Studios 2010.
I have a master grid. In that master grid I have a group bar which you can select different items. Depending on what you select, the middle of the master grid can be totally different. What I was wondering is, what's the best way to program the middle part?
Right now, I have it set up in such a way that everything in the middle is dynamically programed in C#, and everything on the outside is programmed in XAML.
In C# I programmed: for each group bar item, there is a grid that goes with it (so that different content can be displayed on it). Each grid is a child of the master grid. Each grid is visible or hidden when necessary. Is this the best way to approach this?
The best example of this is in Outlook 2007, where you have your group bar on the right hand side. When you select different items on the group bar (mail, calendar, tasks) the right of the group bar completely changes.
The easy way to do this in WPF is to define DataTemplates for each of your "middle" sections.
Using the Outlook example, you might have a MessageCollection class that stores a list of messages, an EventCollection class that stores a list of calendar events, and a TaskCollection class that stores a list of tasks.
In your "middle" area you would simply have a single ContentPresenter whose Content would be set to a MessageCollection, EventCollection, or TaskCollection. Presumably this would be done using a binding to a view model property.
Here is how it might look:
<Window ...>
<Grid>
<!-- group bar area -->
...
<!-- "middle" area -->
<ContentPresenter Grid.Row="1" Grid.Column="1"
Content="{Binding SelectedCollection}" />
</Grid>
</Window>
Now you create a DataTemplate for each of the collection types, for example:
<DataTemplate TargetType="{x:Type my:MessageCollection}">
<Grid>
... put the XAML for displaying mailbox contents here ...
</Grid>
</DataTemplate>
<DataTemplate TargetType="{x:Type my:EventsCollection}">
<Grid>
... put the XAML for displaying a calendar here ...
</Grid>
</DataTemplate>
<DataTemplate TargetType="{x:Type my:TasksCollection}">
<Grid>
... put the XAML for displaying a to-do list here ...
</Grid>
</DataTemplate>
With this setup, all you have to do to switch the inner grid is to set your "SelectedCollection" property in your view model to a different collection type.

Categories