Silverlight vs WPF - Treeview with HierarchialDataTemplate - wpf

So, the following is easy enough in WPF, but how would you do it in Silverlight?
Please note that the trick here is to display both Groups, and Entries on the same level.
Additonally you dont know how deep the entries are nested, they might be on the first, or the nth level.
This is hard in Silverlight because you lack the DataType="{x:Type local:Group}" property in the H.DataTemplate (or any DataTemplate). Building my own custom DataTempalteSelector also didnt work, because the Hierarchial ItemsSource gets lost. (Which just gave me a new idea which I will investigate shortly)
Example:
Group1
--Entry
--Entry
Group2
--Group4
----Group1
------Entry
------Entry
----Entry
----Entry
--Entry
--Entry
Group3
--Entry
--Entry
Your Classes:
public class Entry
{
public int Key { get; set; }
public string Name { get; set; }
}
public class Group
{
public int Key { get; set; }
public string Name { get; set; }
public IList<Group> SubGroups { get; set; }
public IList<Entry> Entries { get; set; }
}
Your xaml:
<TreeView Name="GroupView" Grid.Row="0" Grid.Column="0" ItemsSource="{Binding}">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:Group}" ItemsSource={Binding Items}">
<TextBlock Text="{Binding Path=Name}" />
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type local:Entry}" >
<TextBlock Text="{Binding Path=Name}" />
</DataTemplate>
</TreeView.Resources>
</TreeView>

The TreeView control from the Silverlight toolkit supports hierarchical data templates.
Check out this article for sample usage, but it looks identical to me to the WPF built in one.
You can download the Silverlight toolkit here.

Here is an example of using the HierarchicalDataTemplate with a HeaderedItemsControl in Silverlight (Songhay.Silverlight.BiggestBox.Views.ClientView.xaml):
<UserControl x:Class="Songhay.Silverlight.BiggestBox.Views.ClientView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
xmlns:sdk="clr-namespace:System.Windows;assembly=System.Windows.Controls"
xmlns:sdkctrls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
xmlns:uriMapper="clr-namespace:System.Windows.Navigation;assembly=System.Windows.Controls.Navigation"
xmlns:v="clr-namespace:Songhay.Silverlight.BiggestBox.Views"
xmlns:m="clr-namespace:Songhay.Silverlight.BiggestBox.ViewModels">
<UserControl.Resources>
<Style x:Key="StackPanelRoot" TargetType="StackPanel">
<Setter Property="Background" Value="Seashell" />
<Setter Property="Height" Value="598" />
<Setter Property="Width" Value="1024" />
</Style>
<Style x:Key="GridRoot" TargetType="Grid">
<Setter Property="Height" Value="570" />
</Style>
<Style x:Key="ClientGridSplitter" TargetType="sdkctrls:GridSplitter">
<Setter Property="Background" Value="#FFE0EEE0" />
<Setter Property="Height" Value="8" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
</Style>
<m:ClientViewModel x:Key="ClientViewModelDataSource" d:IsDataSource="True"/>
<Style TargetType="sdkctrls:HeaderedItemsControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="sdkctrls:HeaderedItemsControl">
<StackPanel>
<ItemsPresenter Margin="10,0,0,0" />
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ScrollViewerIndexItems" TargetType="ScrollViewer">
<Setter Property="Margin" Value="10" />
<Setter Property="VerticalScrollBarVisibility" Value="Auto" />
</Style>
<Style x:Key="StackPanelIndexItems" TargetType="StackPanel">
<Setter Property="Background" Value="#ff9" />
<Setter Property="Orientation" Value="Horizontal" />
</Style>
</UserControl.Resources>
<UserControl.DataContext>
<Binding Source="{StaticResource ClientViewModelDataSource}"/>
</UserControl.DataContext>
<Border BorderBrush="Black" BorderThickness="1" VerticalAlignment="Center">
<StackPanel x:Name="RootPanel" Style="{StaticResource StackPanelRoot}">
<Grid Style="{StaticResource GridRoot}">
<Grid.RowDefinitions>
<RowDefinition MinHeight="128" MaxHeight="360" Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="1.5*" />
</Grid.RowDefinitions>
<v:HeaderView Grid.Row="0" />
<sdkctrls:GridSplitter Grid.Row="1" Style="{StaticResource ClientGridSplitter}" />
<StackPanel Grid.Row="2"
Orientation="Horizontal"
Style="{StaticResource StackPanelIndexItems}">
<ScrollViewer Style="{StaticResource ScrollViewerIndexItems}">
<sdkctrls:HeaderedItemsControl
Header="{Binding IndexTitle}"
ItemsSource="{Binding Outlines}">
<sdkctrls:HeaderedItemsControl.HeaderTemplate>
<DataTemplate>
<TextBlock FontSize="24" FontWeight="Bold" Text="{Binding}" />
</DataTemplate>
</sdkctrls:HeaderedItemsControl.HeaderTemplate>
<sdkctrls:HeaderedItemsControl.ItemTemplate>
<sdk:HierarchicalDataTemplate>
<StackPanel>
<TextBlock FontSize="12" FontWeight="Bold" Margin="0,10,0,0" Text="{Binding Text}" />
<sdkctrls:HeaderedItemsControl ItemsSource="{Binding Outlines}" Margin="10,0,10,0">
<sdkctrls:HeaderedItemsControl.ItemTemplate>
<sdk:HierarchicalDataTemplate>
<HyperlinkButton
ClickMode="Press"
Command="{Binding IndexItemCommand, Source={StaticResource ClientViewModelDataSource}}"
CommandParameter="{Binding Url}"
FontSize="12">
<HyperlinkButton.Content>
<TextBlock Text="{Binding Text}" />
</HyperlinkButton.Content>
</HyperlinkButton>
</sdk:HierarchicalDataTemplate>
</sdkctrls:HeaderedItemsControl.ItemTemplate>
</sdkctrls:HeaderedItemsControl>
</StackPanel>
</sdk:HierarchicalDataTemplate>
</sdkctrls:HeaderedItemsControl.ItemTemplate>
</sdkctrls:HeaderedItemsControl>
</ScrollViewer>
<navigation:Frame x:Name="IndexFrame" Width="685">
</navigation:Frame>
</StackPanel>
</Grid>
<v:FooterView Height="30" />
</StackPanel>
</Border>
</UserControl>

Related

How to create a custom control which is a combobox with group header

I have a special requirement which need to implement a combobox which list data in groups and I could do it as below
the XAML file
<Window x:Class="GroupComboBox.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ComboBox x:Name="comboBox" Width="100">
<ComboBox.Resources>
<Style TargetType="{x:Type ComboBox}">
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True" Orientation="Horizontal" Width="150" Height="Auto" >
<!-- add scroll bar -->
</WrapPanel>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type ComboBoxItem}">
<Setter Property="Width" Value="50" />
</Style>
</ComboBox.Resources>
<ComboBox.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<Border BorderBrush="Black" BorderThickness="2">
<TextBlock Text="{Binding Name}" HorizontalAlignment="Stretch" Background="YellowGreen"/>
</Border>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ComboBox.GroupStyle>
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Item}" Width="40"/>
</DataTemplate>
</ComboBox.ItemTemplate>
<ComboBox.ItemContainerStyle>
<Style TargetType="{x:Type ComboBoxItem}">
<Setter Property="IsEnabled" Value="{Binding Available}"/>
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
</Grid>
</Window>
The code-behind file
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
List<CategoryItem<string>> items = new List<CategoryItem<string>>();
for (int i = 0; i < 18; ++i)
{
items.Add(new CategoryItem<string> { Item = string.Format("{0:D2}", i), Available = (i > 9), Category = "Group A" });
}
for (int i = 0; i < 4; ++i)
{
items.Add(new CategoryItem<string> { Item = string.Format("{0:D2}", i), Available = (i > 2), Category = "Group B" });
}
//Need the list to be ordered by the category or you might get repeating categories
ListCollectionView lcv = new ListCollectionView(items.OrderBy(w => w.Category).ToList());
//Create a group description
lcv.GroupDescriptions.Add(new PropertyGroupDescription("Category"));
this.comboBox.ItemsSource = lcv;
}
}
public class CategoryItem<T>
{
public T Item { get; set; }
public bool Available { get; set; }
public string Category { get; set; }
}
Now I want to make the combobox to be a custom control, then it can be reused easily, but I am new for creating custom control and how should I do?
Currently I have created a WPF custom control library and change the base class of the custom control to be 'ComboBox' , but I do not know how to move the styles and templates to the resource dictionary file correctly
I can offer the following variant. Move all the styles and templates in resources:
<!-- Main style for ComboBox -->
<Style x:Key="MyComboBox" TargetType="{x:Type ComboBox}">
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="Width" Value="100" />
<Setter Property="Height" Value="25" />
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True" Orientation="Horizontal" Width="150" Height="Auto" />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{Binding Item}" Width="40"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Style for ComboBoxItem -->
<Style TargetType="{x:Type ComboBoxItem}">
<Setter Property="Width" Value="50" />
</Style>
<!-- Style for ItemContainerStyle -->
<Style x:Key="ComboBoxItemContainerStyle" TargetType="{x:Type ComboBoxItem}">
<Setter Property="IsEnabled" Value="{Binding Available}" />
</Style>
<!-- DataTemplate for HeaderTemplate -->
<DataTemplate x:Key="MyHeaderTemplate">
<Border BorderBrush="Black" BorderThickness="2">
<TextBlock Text="{Binding Name}" HorizontalAlignment="Stretch" Background="YellowGreen" />
</Border>
</DataTemplate>
Using of ComboBox with our styles:
<ComboBox x:Name="MyComboBox1" Style="{StaticResource MyComboBox}" IsSynchronizedWithCurrentItem="False" ItemContainerStyle="{StaticResource ComboBoxItemContainerStyle}">
<ComboBox.GroupStyle>
<GroupStyle HeaderTemplate="{StaticResource MyHeaderTemplate}" />
</ComboBox.GroupStyle>
</ComboBox>
<ComboBox x:Name="MyComboBox2" Style="{StaticResource MyComboBox}" IsSynchronizedWithCurrentItem="False" ItemContainerStyle="{StaticResource ComboBoxItemContainerStyle}">
<ComboBox.GroupStyle>
<GroupStyle HeaderTemplate="{StaticResource MyHeaderTemplate}" />
</ComboBox.GroupStyle>
</ComboBox>
And set the data in code:
this.MyComboBox1.ItemsSource = lcv;
this.MyComboBox2.ItemsSource = lcv;
Set styles for you control need to change Type and write your control name:
<Style x:Key="MyControlComboBox" TargetType="{x:Type local:MyControlComboBox}">
</Style>

Switch ContentPresenter of ListBoxItem Based on Selection

I am trying to switch out the ContentPresenter of a ListBoxItem when it is selected, while using multiple DataTemplates to represent different types of data.
Here is the UserControl that defines the ListBox inside:
<UserControl x:Class="Homage.View.FilePanelView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vw="clr-namespace:Homage.View"
xmlns:vm="clr-namespace:Homage.ViewModel"
xmlns:ctrl="clr-namespace:Homage.Controls"
mc:Ignorable="d">
<UserControl.Resources>
<DataTemplate DataType="{x:Type vm:SlugViewModel}">
<vw:SlugView />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:HeaderSlugViewModel}">
<vw:HeaderSlugView />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:ContentSlugViewModel}">
<vw:ContentSlugView />
</DataTemplate>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Border Name="SlugContainer" Background="Transparent" BorderBrush="Black" BorderThickness="1" CornerRadius="2" Margin="0,5,0,0" Padding="5">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Content="{Binding DisplayName}" />
<ContentPresenter Grid.Row="1" />
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="SlugContainer" Property="BorderThickness" Value="5" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<Grid>
<ListBox ItemsSource="{Binding Slugs}" Padding="5" />
</Grid>
</UserControl>
Based on the type of data to be shown (e.g., a "Header Slug") a certain DataTemplate is applied to the ListBoxItem. This is working great, but I am wanting to adjust the DataTemplate of the selected ListBoxItem to a different DataTemplate -- again, based on the data type being shown.
The goal is that, because each data type is different, each would have a unique look when not selected and would receive a unique set of options when selected.
If I can get the above to work, that would be great! But, I also want to complicate things...
While each data type has unique controls they also have common controls. So I would ideally like to define all the common controls once so that they appear in the same place in the ListBox.
<DataTemplate x:Key="CommonSelectedTemplate">
<!-- common controls -->
...
<DataTemplate x:Key="UniqueSelectedTemplate">
<!-- all the unique controls -->
<ContentPresenter />
</DataTemplate>
<!-- more common controls -->
...
</DataTemplate>
If I have to define all the common stuff multiple times (for now) I'll live. =)
Thanks for any help!
Let's suppose that we have only two data types: Item1ViewModel and Item2ViewModel. Therefore we need 4 data templates: 2 for the common state, 2 for the selected state.
<DataTemplate x:Key="Template1" DataType="local:Item1ViewModel">
<TextBlock Text="{Binding Property1}" Foreground="Red" />
</DataTemplate>
<DataTemplate x:Key="Template2" DataType="local:Item2ViewModel">
<TextBlock Text="{Binding Property2}" Foreground="Blue" />
</DataTemplate>
<DataTemplate x:Key="Template1Selected" DataType="local:Item1ViewModel">
<TextBlock Text="{Binding Property1}" Background="Yellow" Foreground="Red" />
</DataTemplate>
<DataTemplate x:Key="Template2Selected" DataType="local:Item2ViewModel">
<TextBlock Text="{Binding Property2}" Background="Yellow" Foreground="Blue" />
</DataTemplate>
For switching the content between two templates based on different types I use the DataTemplateSelector class:
public class SampleTemplateSelector:DataTemplateSelector
{
public DataTemplate Type1Template { get; set; }
public DataTemplate Type2Template { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
if (item is Item1ViewModel)
return Type1Template;
else if (item is Item2ViewModel)
return Type2Template;
return null;
}
}
We need two instances of this selector: one for the common state and one for the selected state.
<local:SampleTemplateSelector x:Key="templateSelector"
Type1Template="{StaticResource Template1}"
Type2Template="{StaticResource Template2}"/>
<local:SampleTemplateSelector x:Key="selectedTemplateSelector"
Type1Template="{StaticResource Template1Selected}"
Type2Template="{StaticResource Template2Selected}"/>
And after that you should add this code which switches two selectors:
<DataTemplate x:Key="ListItemTemplate">
<ContentControl x:Name="content" Content="{Binding}" ContentTemplateSelector="{StaticResource templateSelector}" />
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type ListBoxItem}},Path=IsSelected}" Value="True">
<Setter TargetName="content" Property="ContentTemplateSelector" Value="{StaticResource selectedTemplateSelector}"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
That's all, apply this ItemTemplate to your ListBox without changing the ControlTemplate:
<ListBox ItemsSource="{Binding Items}" ItemTemplate="{StaticResource ListItemTemplate}" />

WPF- Validation -The validation error message goes behind the other controls because of AdornerDecorator

I have implemented IDataErrorInfo in my ViewModel to return a string if the text box has error.
public string this[string columnName]
{
get { return "Error-- This is a long error message - sd"; }
}
But this error message goes behind the other control on the UI as shown below.
Below is the xaml:
<Window x:Class="Test.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="600" Width="600">
<Window.Resources>
<ControlTemplate x:Key="validationTemplateNew">
<DockPanel LastChildFill="True">
<TextBlock Name="ErrorText" DockPanel.Dock="Bottom" Foreground="White" Background="Red"
FontSize="12" Padding="2" FontFamily="Trebuchet MS"
Margin="5,5,0,0"
TextWrapping="Wrap"
Text="{Binding [0].ErrorContent}" ></TextBlock>
<AdornedElementPlaceholder Name="ErrorTextBox" />
</DockPanel>
</ControlTemplate>
<Style x:Key="ValidationStyle" TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="BorderBrush" Value="Red" />
<Setter Property="BitmapEffect">
<Setter.Value>
<BitmapEffectGroup>
<OuterGlowBitmapEffect GlowColor="Red" GlowSize="3" Noise="0.6"></OuterGlowBitmapEffect>
</BitmapEffectGroup>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<ItemsControl Name="ItemCtrl">
<AdornerDecorator>
<TextBox
FontSize="11"
Margin="10"
Width="250"
VerticalAlignment="Center"
Text="{Binding Path=StrText, ValidatesOnDataErrors=True,
UpdateSourceTrigger=PropertyChanged}"
Validation.ErrorTemplate="{StaticResource validationTemplateNew}"
Style="{StaticResource ValidationStyle}"
>
</TextBox>
</AdornerDecorator>
<TextBox Width="250" Text="ASDFASFASDFASDFASDFASDFASDF"/>
<TextBox Width="250" Text="ASDFASFASDFASDFASDFASDFASDF"/>
<TextBox Width="250" Text="ASDFASFASDFASDFASDFASDFASDF"/>
<TextBox Width="250" Text="ASDFASFASDFASDFASDFASDFASDF"/>
<TextBox Width="250" Text="ASDFASFASDFASDFASDFASDFASDF"/>
</ItemsControl>
</Grid>
</Window>
Please let me know how to use AdornerDecorator such that the error message overlaps the other controls and doesn't go behind.
My application is such that if I don't use AdornerDecorator, the error message is not displayed at all.
Adding Grid.ZIndex on the AdornerDecorator should be enough
<Grid>
<ItemsControl Name="ItemCtrl">
<AdornerDecorator Grid.ZIndex="1">

WPF Tooltip Binding

I am only two weeks into WPF so this is probably a trivial question. I have a collection "CellList" which has a few properties I would like to bind to a ToolTip so when I hover over a label information from the current instance of CellList is displayed. How do I do that? I understand simple binding and this maybe simple binding too but I can't wrap my head around it. Below is my XAML for the label. Could someone explain to me how I can accomplish this.
<HierarchicalDataTemplate>
<ListBox ItemsSource="{Binding CellList}">
<ListBox.ItemTemplate>
<DataTemplate>
<Label Content=" " Height="20" Width="15" Background="{Binding Path=ExptNameBkg, Converter={StaticResource ExptNameToBrushConverter}}" BorderBrush="Black" BorderThickness="1" >
</Label>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</HierarchicalDataTemplate>
Thanks.
The tricky thing about ToolTips is that a ToolTip is an object you associate with a control, and not part of the control's visual tree. So you can't populate it the way you'd populate things in the visual tree, e.g.:
<TextBox.ToolTip>
<StackPanel>
...put bound controls here
</StackPanel>
</TextBox.ToolTip>
Instead, what you have to do is create a specific instance of a ToolTip, and assign it a style that sets its DataContext (very important; that's how you can bind to the properties of the data source of its "placement target," i.e. the control that's displaying the tooltip) and its Template. Then put the visual tree of the ToolTip, including bindings, into the template. Finally, reference the ToolTip in your control.
So, here's a TextBox whose Binding does validation:
<TextBox ToolTip="{StaticResource ErrorToolTip}">
<TextBox.Text>
<Binding Source="SourceProperty">
<Binding.ValidationRules>
<DataErrorValidationRule/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
It uses this ToolTip:
<ToolTip x:Key="ErrorToolTip" Style="{StaticResource ErrorToolTipStyle}"/>
And the ToolTip uses this style, which gets its content from the ValidationError property of the TextBox's binding source:
<Style x:Key="ErrorToolTipStyle" TargetType="{x:Type ToolTip}">
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="HasDropShadow" Value="True"/>
<Setter Property="DataContext" Value="{Binding Path=PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToolTip">
<Border
Name="Border"
BorderThickness="1"
BorderBrush="LightGray">
<StackPanel Orientation="Vertical">
<Label Background="Firebrick" Foreground="White" FontWeight="Bold" Margin="4">Validation error</Label>
<TextBlock Margin="10" Text="{Binding ValidationError}"/>
</StackPanel>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="HasDropShadow" Value="true">
<Setter TargetName="Border" Property="CornerRadius" Value="4"/>
<Setter TargetName="Border" Property="SnapsToDevicePixels" Value="true"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I'm not certain of this, but I think that the only part of the above that actually has to be set in the style is the DataTrigger setting the DataContext; I think most everything else could just be explicitly set in the ToolTip's visual tree. But I'm probably not thinking of something important.
<Label Content={Binding Path=Id} ToolTip={Binding Path=Name}/>
just try this
Here's a kaxaml-ready example that includes a tooltip that is a little more elaborate than just text:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<XmlDataProvider x:Key="CharacterData">
<x:XData>
<Data xmlns="">
<Character First="Bart" Last="Simpson" Background="LightGreen" />
<Character First="Homer" Last="Simpson" Background="LightBlue" />
<Character First="Lisa" Last="Simpson" Background="Pink" />
<Character First="Maggie" Last="Simpson" Background="Yellow" />
<Character First="Marge" Last="Simpson" Background="PapayaWhip" />
</Data>
</x:XData>
</XmlDataProvider>
<ToolTip x:Key="ElaborateToolTip">
<Grid Margin="5">
<Rectangle RadiusX="6" RadiusY="6" Fill="{Binding XPath=#Background}" />
<StackPanel Orientation="Horizontal" Margin="10">
<TextBlock Text="{Binding XPath=#First}" Margin="0,0,6,0" />
<TextBlock Text="{Binding XPath=#Last}" />
</StackPanel>
</Grid>
</ToolTip>
</Page.Resources>
<ListBox ItemsSource="{Binding Source={StaticResource CharacterData}, XPath=Data/Character}">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="ToolTip" Value="{StaticResource ElaborateToolTip}" />
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding XPath=#First}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Page>

In WPF, Selecting ItemContainerStyle based on data bound content

In #WPF you have ItemTemplateSelectors. But, can you also select an ItemContainerStyle based on the datatype of a bound object?
I am databinding a scatterview. I want to set some properties of the generated ScatterViewItems based on the object in their DataContext. A mechanism similar to ItemTemplateSelector for styles would be great. Is that at all possible? I am now binding to properties in the objects that I am displaying to get the effect, but that feels like overhead and too complex (and most importantly, something that our XU designers can't do by themselves).
This is the XAML that I am using now. Your help is greatly appreciated.
<s:ScatterView x:Name="topicsViewer">
<s:ScatterView.ItemTemplateSelector>
<local:TopicViewerDataTemplateSelector>
<DataTemplate DataType="{x:Type mvc:S7VideoTopic}">
<Grid>
<ContentPresenter Content="{Binding MediaElement}" />
<s:SurfaceButton Visibility="{Binding MailToVisible}" x:Name="mailto" Tag="{Binding Titel}" Click="mailto_Click" HorizontalAlignment="Right" VerticalAlignment="Top" Background="Transparent" Width="62" Height="36">
<Image Source="/Resources/MailTo.png" />
</s:SurfaceButton>
<StackPanel Orientation="Horizontal" VerticalAlignment="Bottom" HorizontalAlignment="Center" Height="32">
<s:SurfaceButton Tag="{Binding MediaElement}" x:Name="btnPlay" Click="btnPlay_Click">
<Image Source="/Resources/control_play.png" />
</s:SurfaceButton>
<s:SurfaceButton Tag="{Binding MediaElement}" x:Name="btnPause" Click="btnPause_Click">
<Image Source="/Resources/control_pause.png" />
</s:SurfaceButton>
<s:SurfaceButton Tag="{Binding MediaElement}" x:Name="btnStop" Click="btnStop_Click">
<Image Source="/Resources/control_stop.png" />
</s:SurfaceButton>
</StackPanel>
</Grid>
</DataTemplate>
<DataTemplate DataType="{x:Type mvc:S7ImageTopic}">
<Grid>
<ContentPresenter Content="{Binding Resource}" />
<s:SurfaceButton Visibility="{Binding MailToVisible}" x:Name="mailto" Tag="{Binding Titel}" Click="mailto_Click" HorizontalAlignment="Right" VerticalAlignment="Top" Background="Transparent" Width="62" Height="36">
<Image Source="/Resources/MailTo.png" />
</s:SurfaceButton>
</Grid>
</DataTemplate>
<DataTemplate DataType="{x:Type local:Kassa}">
<ContentPresenter Content="{Binding}" Width="300" Height="355" />
</DataTemplate>
</local:TopicViewerDataTemplateSelector>
</s:ScatterView.ItemTemplateSelector>
<s:ScatterView.ItemContainerStyle>
<Style TargetType="s:ScatterViewItem">
<Setter Property="MinWidth" Value="200" />
<Setter Property="MinHeight" Value="150" />
<Setter Property="MaxWidth" Value="800" />
<Setter Property="MaxHeight" Value="700" />
<Setter Property="Width" Value="{Binding DefaultWidth}" />
<Setter Property="Height" Value="{Binding DefaultHeight}" />
<Setter Property="s:ScatterViewItem.CanMove" Value="{Binding CanMove}" />
<Setter Property="s:ScatterViewItem.CanScale" Value="{Binding CanScale}" />
<Setter Property="s:ScatterViewItem.CanRotate" Value="{Binding CanRotate}" />
<Setter Property="Background" Value="Transparent" />
</Style>
</s:ScatterView.ItemContainerStyle>
</s:ScatterView>
Bart Roozendaal, Sevensteps
How about using a ItemContainerStyleSelector (duh!)... Sorry, it's been a long night

Resources