How to render different template for some tabs in WPF? - wpf

I have a tab content template set to my tab control:
<TabControl SelectedIndex="0"
ItemsSource="{Binding Tabs}"
ItemTemplate="{StaticResource AppTabItemTemplate}"
ContentTemplate="{StaticResource AppTabContentTemplate}" />
The thing is that most of the times the current template is wanted, but there are times when I want to display another template instead. The item source provides this data whether it should show one or another, but how can I do an "if" in XAML and use an alternative UI when the other layout is wanted?
Should this logic be part of the template or the containing XAML that includes this tab control? The information that is used to make the decision between UIs is in the item source.

Use a DataTemplateSelector.
You will need to define your selection logic in a class that derives DataTemplateSelector, create a resource for your selector in XAML and then use it by assigning the resource to the ItemTemplateSelector property of your tab control.

Related

WPF Data Template Selector

I have a data template selector, which I am using to pick between two different templates. Problem is, these templates include a grid as the outer element etc. What I have done is I have my template selector in my resource control in my UserControl.Resources:
<l:UIDataTemplateSelector x:Key="UISelector"
ClassicDataTemplate="{StaticResource ClassicDataTemplate}"
ModernDataTemplate="{StaticResource ModernDataTemplate}" />
Then outside of this, I have my Content Control, where my templates are in Control Templates:
<ContentControl ContentTemplateSelector="{StaticResource UISelector}"></ContentControl>
When I run my code, this causes it to crash, but if I use:
<ContentControl Template="{StaticResource ClassicDataTemplate}"></ContentControl>
To use one template or the other, it works perfectly fine. Is there a simple way to get it to use the template selector to display it?
A ContentControl has a Template of type ControlTemplate. It also accepts a ContentTemplate of type DataTemplate and a ContentTemplateSelector which is expected to select a DataTemplate. In your case, since Template="{StaticResource ClassicDataTemplate}" is working, I suspect you created ControlTemplate instead of DataTemplate. You need a working ContentTemplate="{StaticResource ClassicDataTemplate}" in order to transfer to the selector.

How to combine multiple xaml pages in one xaml page?

Is there any idea of master layout and child layouts in wpf for xaml pages?
I have one xaml file which I want to use in two different Xaml files with different Data but same UI.
I don't want to create same design two times, I just want to have only one xaml page on both places.
Use a ContentControl with different ContentTemplate. Define these ContentTemplate as Resource. Specify DataType in the DataTemplate of your ContentTemplate. And in different places just set appropriate Content of your ContentControl using Binding. This Content can be any property of any kind.
Eg;
<ContentControl Content="{Binding View1}" />
<ContentControl Content="{Binding View2}" />
Beauty is DataTemplate is automatically picked up by the ContentControl.

How to reuse Menu and Toolbar in different WPF UserControls with adding new buttons?

I'm trying to port current WinForms app to WPF and need help with building WPF class structure.
Currently in WinForms, I have one base class (with Menu, Toolbar, Grid and Context menu) and several inherited classes with different datasources and columns for the grid and additional buttons for menu, toolbar and context menu.
Questions:
What will be the best WPF class structure for my usercontrol to avoid inheritance?
Can I move ToolBar into ResourceDictionary (e.g. ControlTemplate)?
How to add new buttons or to bind commands to existed buttons, if buttons will be specified in a separate resource file?
Any other ideas?
Due to inheritance restrictions in WPF I see only one way to avoid duplicating Menu, Toolbar, etc. - implement base class in C# code only without XAML. And likely I can't use XAML for inherited classes as well (have no idea how to add new buttons in XAML into Toolbar created in base class)
In WPF a Toolbar is an ItemsControl (same for Menu), so it has an ItemsSource property you can bind to your collection of toolbar items.
<Window.Resources>
<DataTemplate x:Key="ItemTemplate1">
<StackPanel>
<TextBlock Text="{Binding Property1}"/>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid x:Name="LayoutRoot" DataContext="{Binding MyViewModel}">
<ToolBar HorizontalAlignment="Left" VerticalAlignment="Top" ItemTemplate="{DynamicResource ItemTemplate1}" ItemsSource="{Binding ToolbarItems}"/>
</Grid>
In this code, ToolbarItems is an ObservableCollection< MyToolBarItem >, where MyToolbarItem is a viewmodel that represents one toolbar item.
MyToolBarItem could be the base class, with several classes inheriting from it. Then you can use a DataTemplateSelector to use a different template depending on the type of toolbar item it is.
In this way, all your user controls that have a toolbar can use the same templates you define in your dictionary; each toolbar is just bound to a different collection of MyToolBarItems.
If some of that sounds overwhelming, you can read up on some MVVM. It is the design pattern that makes WPF great.

Grid with content from Binding

I have a library that generates a Grid based on input parameters. The Grid may contain different controls based on the input. I want to create a ListBox where each list item will get its own generated Grid. Is this doable? I couldnt find any Panel-derived (Gird, StackPanel etc) that expose the Content property like Button for example.
How are you passing the data to build the Grid?
I'll assume you have a control that receives the data via a Dependency Property. I.e. you have something like MyControl.MyData property, where MyData is a Dependency Property. In that case, try using a DataTemplate.
Make an ObservableCollection where each item is the data you need to pass in order to build the grid.
On the instance of the ListBox, define ItemTemplate to use a DataTemplate consisting of your control.
<ListBox>
<ListBox.ItemTemplate>
<DataTemplate>
<myAssembly:MyControl MyData="{Binding }"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
#XAMeLi is almost right on the money with his answer - what would be better is a DataTemplateSelector, that way each data item can have a different template (or generated grid). In your class that extends DataTemplateSelector you can easily generate or load the appropriate grid layout as either a separate control or as a dynamic DataTemplate.
Check this article for a good example: WPF Tutorial - How To Use A DataTemplateSelector

Is it possible to create a WPF tab control template that looks nothing like a tab control?

What I'd like is a control that functions just like the tab control but instead of having the tabs along the top, the items would be displayed in a list box along the side. I imagine it's possible but haven't found any examples, I'm hoping there's someone here that's done something like this.
WPF controls are designed to enable exactly what you want. To reuse control functionality while completely replacing the visual representation. You will have to create your own ControlTemplate for the TabControl. You can find a TabControl ControlTemplate Example on MSDN. You will also have to study the Control Authoring Overview on MSDN.
I actually find the Silverlight 3 documentation somewhat easier to digest, and even though there are some differences when it comes to control styling the fundamental concepts are still the same. You can read Customizing the Appearance of an Existing Control by Using a ControlTemplate on MSDN to learn about control templates and then study TabControl Styles and Templates to discover what is required to create you own control template in Silverlight.
You can use Expression Blend to extract the the default TabControl template in WPF.
You don't need to use a TabControl at all. You could just bind your ListBox to a list of items, and put a ContentControl beside it, bound to the selected item :
<DockPanel>
<ListBox Name="listBox"
DockPanel.Dock="Left"
ItemsSource="{Binding Items}"
DisplayMemberPath="Name"/>
<ContentControl Content="{Binding SelectedItem, ElementName=listBox}"
ContentTemplate="{StaticResource theTemplate}"/>
</DockPanel>

Resources