WPF Tabcontrol DataTemplate and child user control initialization - wpf

I have a view with a TabControl and the content of each tab is defined as a Resource in TabControl.Resources. In this content, I have a user control which basically contains a datagrid.
<TabControl ItemsSource="{Binding MyTabs}"
SelectionChanged="TabSelected">
<TabControl.Resources>
<DataTemplate DataType="{x:Type uc:Tab}">
<uc:MyUserControlWithDatagrid />
</DataTemplate>
</TabControl.Resources>
</TabControl>
To my surprise, I notice that even if I have multiple tab items, I only enter once in MyUserControlWithDatagrid's constructor. I am guessing that it is "shared" between all tab items?
If that is correct, how can I make it so that a usercontrol instance is created for each tab item?

You may want to read this article about the virtualization of tabs.
You can download the code samples from here.
The solution proposed enables you to define a custom template:
<TabControl ikriv:TabContent.IsCached="True">
<ikriv:TabContent.Template>
<DataTemplate>
<!-- custom content template goes here -->
</DataTemplate>
</ikriv:TabContent.Template>
</TabControl>

Related

WPF TabControl, switching to another TabItem does not work, sticks to first TabItem

I have a control that contains following XAML code. It works fine excepted that I caInnot switch to another TabItem. I read that TabControl virtualizes the TabItem, I suspect the strange behaviour, namely that I cannot get to display any other TabItem as the first one, is related to this.
<TabControl ItemsSource="{Binding Items}">
<TabControl.ItemTemplate>
<DataTemplate> <!-- header -->
<TextBlock Text="{Binding Title}"></TextBlock>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate x:Shared="False"> <!-- tabitem content -->
<controls:ItemControl Item="{Binding}" />
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
I tried to set the x:Shared attribute of the DataTemplate to False but has not the expected effect. Is there a way to reach this without going the way of using a custom style and replacing the TabControl with an ItemsControl. I mean the functionality of TabControl is what I would like, I would like to simply use it with ItemsSource binding...
This behaviour will happen if you are binding to a collection that has duplicate objects in it.
Duplication can occur due to having added an object multiple times or because equality has been redefined for the objects in question.

WPF Creating types of Tabitems in tabcontrol

i need to create types of Tabitems to my tabcontrol.
each tab will have different content and functionalities (Xaml and code-behind).
For Example, i want to create:
* Customer details tab - with fields of customer detials.
* Configuration tab - fields for configuring the application.
* Statistics tab - table and graphs with statistics.
Sometimes two or three tabs of each tabitem type will be open.
i don't want to copy paste the TabItem.Content again and again for same customer tab or other.
i want to make a type of tab.
what is the best way to create such tabitem types ?
Usually I store my TabItemViewModels in a ParentViewModel, and use a DataTemplate to define how each ViewModel should be displayed.
<Window.Resources>
<DataTemplate DataType="{x:Type local:CustomerDetailsViewModel}">
<local:CustomerDetailsView />
</DataTemplate>
<DataTemplate DataType="{x:Type local:ConfigurationViewModel}">
<local:ConfigurationView />
</DataTemplate>
<DataTemplate DataType="{x:Type local:StatisticsViewModel}">
<local:StatisticsView />
</DataTemplate>
</Window.Resources>
<TabControl ItemsSource="{Binding TabList}" SelectedItem="{Binding SelectedTab}" />

How to expose ItemTemplate and ContentTemplate from a UserControl

I have written a Well control, similar to the Visual Studio editor tabs so that a user can have multiple documents open and can see one or more at a time. It is derived from a UserControl and exposes an ObservableCollection of OpenDocuments that binds to the ViewModel. If I were to implement this as a simple TabControl, then this would be how it would look:
<TabControl
Grid.Row="1"
Grid.Column="1"
ItemsSource="{Binding OpenDocuments}"
SelectedItem="{Binding SelectedTab, Mode=TwoWay}">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock
Text="{Binding Name}" />
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<vw:DocumentView />
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
This gives me Name in the tabitem header and the DocumentView (another user control in the Content area).
My control has a ContentTemplate but it is of course representing the whole of the control so all I get to see is the DocumentView. My control doesn't have an ItemTemplate.
How do I expose an ItemTemplate and ContentTemplate?
Andrew
EDIT -------------------------------------------------------------------------
Thanks for the replies. It looks like this:
A user can have one or more document wells holding one or more tabs. All the consumer has access to is the list of visible tabs and the currently selected tabitem.
Notice that the tabs are all empty! I don't understand how to specify the ContentTemplate for the <vw:DocumentView> in the same way as the TabControl example above.
Andrew
I am a little confused on exactly what your control looks like but here is what I think you are after.
If your control can inherit from ItemsControl you will get the ItemTemplate property already defined for you. All you have to do in your control template is to Template bind the ItemsControl property to the correct place in the template.
The same applies for the ContentTemplate. If you have the a ContentTemplate property already defined for you control you just need to Template Bind it to the correct place in the control.
It would look something like this
Control Consumer
<MyControlNamespace:MyControl ContentTemplate="{StaticResource MyContentTemplate}" ItemTemplate="{StaticResource MyItemTemplate}" />
Implementation of "MyControl" from above (totally pseudo code)
<MyControl>
<ItemsPresenter ItemTemplate="{TemplateBinding ItemTemplate}" />
<ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}" />
</MyControl>
Again, my example doesn't fully make sense but I am not sure what your control looks like and not entirely sure what you are asking, but hopefully this helps.

Use a user control as a DataTemplate within a WPF application

I am trying to create a user control within a WPF application that will serve as a DataTemplate for a ListBoxItem. The user control a grid with 4 TextBlocks. This control also contains other shapes and images more for visual aid than anything so I am omitting them from the code in this question for clarity.
When I drop the user control on my mainwindow.xaml I can see the control and the properly bound fields point to the first record in the datasource. What I want to do is have this control render repeatedly within either a listbox or a wrap panel for each record within the database.
Can anyone provide me with a pointer or sample of how to have a user control render as a DataTemplate within the ListBox control/other panel.
Up to this point I have tried the following with no avail:
Thanks in advance for any tips.
<!--within Window.Resource -->
<DataTemplate x:Key="myActivity">
<local:ucActivityItm /> <!--usercontrol -->
</DataTemplate>
<!-- Listbox within the window -->
<ListBox HorizontalAlignment="Stretch" ItemTemplate="{DynamicResource myActivity}" VerticalAlignment="Stretch">
<ListBoxItem>
<!-- control also added for testing to ensure it rendered out-->
<local:ucActivityItm />
</ListBoxItem>
</ListBox>
That DataTemplate isn't actually being assigned to your ListBox. There's three ways:
1: Replace the template in the Resources section with
<ListBox.ItemTemplate>
<DataTemplate>
<local:ucActivityItm />
</DataTemplate>
</ListBox.ItemTemplate>
in the ListBox.
2: Somewhat related:
<ListBox ... ItemTemplate="{StaticResource myActivity}">
3: Set the DataType parameter of the DataTemplate above to whatever the content of your ListBox is.
<DataTemplate x:Key="myActivity" DataType="{x:Type ...}">
I usually just do the first, but any should work.

How to bind items of a TabControl to an observable collection in wpf?

What is the simplest example of binding the items of a TabControl to an ObservableCollection?
Each tab's content will have unique data, and indeed this data will have observableCollections of its own bound to the items components.
Currently I have a user control, which I would like to set as the content of each tab as soon as it is created. I also need to dynamically set the datacontext of this new user control when the tab is created. So, essentially, I would like the tabcontrol's observablecollection contain modelviews that map to the data in each tab.
On top of that, I need to do all this without violating MVVM in WPF! Any help?
Much appreciated!
Basic example :
<Window.Resources>
<DataTemplate x:Key="templateForTheContent" DataType="{x:Type vm:TheViewModelType}">
<v:YourUserControl/>
</DataTemplate>
<DataTemplate x:Key="templateForTheHeader" DataType="{x:Type vm:TheViewModelType}">
<TextBlock Text="{Binding ThePropertyToDisplayInTheHeader}"/>
</DataTemplate>
</Window.Resources>
...
<TabControl ItemsSource="{Binding YourCollection}"
ContentTemplate="{StaticResource templateForTheContent}"
ItemTemplate="{StaticResource templateForTheHeader}">
</TabControl>

Resources