Use a user control as a DataTemplate within a WPF application - wpf

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.

Related

WPF Tabcontrol DataTemplate and child user control initialization

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>

WPF listbox OO data template

This is a basic question but I'm just coming back to WPF after a long break and can't remember how to do this. I've tried looking around but can't find exactly the answer I'm looking for.
I have a Listbox control that I want to bind to a List<TradeViewModel> collection. I want the ListBoxItems to pick up that the items are of type TradeViewModel and based on that, to use a custom data template including a checkbox that is bound to TradeViewModel.IsChecked and for the text of the row to be TradeViewModel.TradeId.
I have created the ViewModel class with exposed dependency properties and INotifyPropertyChanged but it's how to hook up the XAML and data templates that I can't quite remember how to do.
Can someone please help me with a quick example?
Thanks!
<ListBox ItemsSource="{Binding YourList}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid> <!-- Or whatever -->
<CheckBox IsChecked="{Binding IsChecked}"/>
<!-- Other UI Elements here -->
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

Switch View based on selected TreeViewItem

I have a Shell.xaml file which contains two other UserControls. On the left is my TreeView and on the right is a detail screen.
I want the detailscreen to be switchable based on a selected TreeViewItem. I know this can be achieved by using DataTemplates, because I've done it with simple button clicks and using the <ContentControl Content="{Binding CurrentDetailViewModel}"> tag to accomplish this, but I have no idea how to accomplish this based on a selected TreeViewItem. I also have a separate ViewModel class for my UserControl which holds my TreeView and a separate for each detail screen.
I've been using Josh Smith's tutorial on TreeViews: http://www.codeproject.com/KB/WPF/TreeViewWithViewModel.aspx
So I also do use the TreeViewItemViewModel.cs class of his.
Could someone shed some light onto this?
Thanks,
Grant
If both the treeview and the details are displaying the same object (i.e the ItemsSource of the treeview contains the objects that you want to data template in the custom control) then you should be able to set a property on an underlying ViewModel that both controls share and have the custom control display something relevant with data templates.
for example, in the ViewModel:
object TreeViewSelectedItem
{
get{ return _treeViewSelectedItem;}
set {_treeViewSelectedItem = value; NotifyPropertyChanged("TreeViewSelectedItem");}
}
Treeview xaml
<TreeView ... SelectedItem={Binding TreeViewSelectedItem Mode=OneWayToSource}".../>
custom control xaml
<UserControl>
<Control.Resources>
<DataTemplate DataType="{x:Type Plane}">
....
</DataTemplate>
<DataTemplate DataType="{x:Type Train}">
....
</DataTemplate>
<DataTemplate DataType="{x:Type Automobile}">
....
</DataTemplate>
</Control.Resources>
<ContentControl Content={Binding TreeViewSelectedItem}"/>
</Usercontrol>

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.

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