Find datacontext inside datatemplate - silverlight

I'm not a Silverlight expert and I'm struggling with an irritating problem.
I have a Telerik RadRichTextbox inside a Grid. This Grid is inside a DataTemplate which is part of an ItemsControl. Like so:
<ItemsControl Grid.Row="1" ItemsSource="{Binding MyCollection}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<telerik:RadRichTextBox x:Name="_Editor" DocumentChanged="HandleditorDocumentChanged"/>
<Xaml:XamlDataProvider x:Name="xamlProvider" Xaml="{Binding Text}" RichTextBox="{Binding ElementName=_Editor}" />
<TextBox Grid.Row="1" Text="{Binding Text2}" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
In the DocumentChanges event I want to access the DataContext of the DataTemplate. I tried setting the DataContext of the _Editor to {Binding} but in the code behind the DataContext is null.
I then thought of getting the parent of the _Editor, which is the Grid. Its DataContext is also null and the Grid its parent is also null.
Any ideas?

I think what' you're looking for is a DataContext Proxy. Consider this example:
http://weblogs.asp.net/dwahlin/archive/2009/08/20/creating-a-silverlight-datacontext-proxy-to-simplify-data-binding-in-nested-controls.aspx

Related

WPF layout problems using Grid and ListBox

I'm (sort of) a newbie in WPF. And I'm stuck with this layout. The Viewbox is displayed fine and so is the space (30%) for ListBox but I can't see ListBox in that space. Following is my XAML, just pertaining to the problem.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="70*"/>
<RowDefinition Height="30*"/>
</Grid.RowDefinitions>
<Viewbox Grid.Row="0" Grid.Column="0" DataContext="{Binding ElementName=thisControl}">
<ItemsControl ItemsSource="{Binding Path=SomeProperty}" ItemTemplate="{StaticResource SomeTemplate}" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Viewbox>
<ListBox Grid.Row="1" Grid.Column="0" ItemTemplate="{StaticResource ListBoxItemTemplate}" ItemsSource="{Binding Path=SomeOtherProperty}" Utils:ListBoxExtenders.AutoScrollToEnd="True"/>
</Grid>
Any help will be greatly appreciated.
It was the DataContext defined at a wrong level. SomeOtherProperty is part of that context without which no data will be bound to the ListBox. But I'm still perplexed as to why there wasn't any binding error in the Output Window for it. Hmmm...

Binding the control's property in its DataTemplate

I have a custom control where I have modified a ListView. I have a DataTemplate which shows each item as an icon of width 128 and a label beneath it.
<DataTemplate x:Key="AeroIconTemplate">
<Grid VerticalAlignment="Top" Margin="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Image Grid.Row="0" Source="{Binding Image}" Width="128"
MaxHeight="128" Margin="0"/>
<TextBlock Grid.Row="1" Text="{Binding Title}" Foreground="Black"
TextWrapping="WrapWithOverflow" Margin="0"
TextTrimming="CharacterEllipsis" Width="128" MaxHeight="60" />
</Grid>
</DataTemplate>
Now I have added a property to the ListView itself called IconSize. This takes an integer between 16 and 256.
I want to bind the Width, MaxHeight of the Image and the Width of the TextBlock to this property. So whenever the IconSize property is changed the template is adjusted in size. As you can see I am currently binding some stuff to the data object (the image source and the label text), but in this case I want to bind to the ListView control.
How do I do this?
Thanks!
You can use the RelativeSource for that:
... Width="{Binding IconSize,RelativeSource={RelativeSource AncestorType=ListView}}" ...
Be sure to define the correct type, since the WPF ListView does not have the property IconSize. You may need to define your class.

What would be an alternative to x:Reference?

I have XAML that looks as follows:
<DataTemplate x:Key="CdTeThickness">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel Grid.Row = "0" Orientation="Horizontal">
<CheckBox x:Name="DisplayMarkers" Content="Display Data Points" Margin="8,5,0,5" HorizontalAlignment="Left" IsChecked="False"/>
<CheckBox x:Name="DisplayIndicator" Content="Display Indicator" Margin="8,5,0,5" HorizontalAlignment="Left" IsChecked="False"/>
</StackPanel>
<vf:Chart Grid.Row = "1" Style="{StaticResource chartStyle}" IndicatorEnabled="{Binding Source={x:Reference DisplayIndicator}, Path=IsChecked}">
<vf:Chart.Titles>
<vf:Title Text="{Binding Chart.ChartTitle}"/>
</vf:Chart.Titles>
My understanding is that x:Reference is not widely supported yet. However, this is the only way I was able to bind to the desired property (DisplayIndicator), as shown in the screen shot. Can someone suggest an alternative to x:Reference that will work in this situation?
Often you can use an ElementName binding, however x:Reference is actually well supported.
{Binding IsChecked, ElementName=DisplayIndicator}
Also, as an alternative to direct binding, you could bind both the Checkbox.IsChecked and the Chart.IndicatorEnabled enabled to a property (e.g. ChartDisplayMarkers) on your viewmodel.

Binding DataTemplates (or another approach)

I'm having some troubles trying to dynamically generate content in WPF and after it bind data.
I have the following scenario:
TabControl
- Dynamically generated TabItems through DataTemplate
- inside TabItems, I have dynamic content generated by DataTemplate that I wish to bind (ListBox).
The code follows:
::TabControl
<TabControl Height="252" HorizontalAlignment="Left" Name="tabControl1" VerticalAlignment="Top" Width="458" Margin="12,12,12,12" ContentTemplate="{StaticResource tabItemContent}"></TabControl>
::The Template for TabControl to generate TabItems
<DataTemplate x:Key="tabItemContent">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ListBox ItemTemplate="{StaticResource listBoxContent}" ItemsSource="{Binding}">
</ListBox>
</Grid>
</DataTemplate>
::The template for ListBox Inside each TabItem
<DataTemplate x:Key="listBoxContent">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="22"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Source="{Binding Path=PluginIcon}" />
<TextBlock Grid.Column="1" Text="{Binding Path=Text}" />
</Grid>
</DataTemplate>
So, when I try to do this on code inside a loop to create the tabitems:
TabItem tabitem = tabControl1.Items[catIndex] as TabItem;
tabitem.DataContext = plugins.ToList();
where 'plugins' is an Enumerable
The ListBox is not bounded.
I tried also to find the ListBox inside the TabItem to set the ItemSource property but no success at all.
How do I do that?
The template for TabControl uses a ContentPresenter to presents the SelectedContent, like this:
<ContentPresenter Content="{TemplateBinding SelectedContent}"
ContentTemplate="{TemplateBinding ContentTemplate}" />
A ContentPresenter's job in life is to expand a DataTemplate. As it does so it sets the DataContext of the constructed visual tree to its Content property, which in this case is bound to SelectedContent.
The SelectedContent is set from the TabItem's Content property, not its DataContext. So setting the DataContext on the TabItem doesn't set the DataContext on the content area's visual tree.
What you want is:
tabItem.Content = plugins.ToList();

Is there any way to programmatically change a Data/ItemTemplate in Silverlight?

I have a Listbox, which is using an ItemTemplate to display an image. I want to be able to change the size of the displayed image in the ItemTemplate. Through databinding I can change the Width, but the only way I can see how to do this is to add a Property (Say, ImageSize) to the class I am binding to and then change every item in the collection to have a new ImageSize. Is there no way to access the property of an item in that Datatemplate?
E.g.
<navigation:Page.Resources>
<DataTemplate x:Key="ListBoxItemTemplate">
<Viewbox Height="100" Width="100">
<Image Source="{Binding Image}"/>
</Viewbox>
</DataTemplate>
</navigation:Page.Resources>
<Grid>
<ListBox ItemTemplate="{StaticResource ListBoxItemTemplate}" ItemSource="{Binding Collection}"/>
</Grid>
Is there anyway to set the Width and Height of the viewbox without binding a property to every element in the collection?
You can use element binding to this. Try something like this:
<UserControl.Resources>
<DataTemplate x:Key="ListBoxItemTemplate">
<Viewbox Height="{Binding Value, ElementName=slider1}"
Width="{Binding Value, ElementName=slider1}">
<Image Source="{Binding Image}"/>
</Viewbox>
</DataTemplate>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="205*" />
<RowDefinition Height="95*" />
</Grid.RowDefinitions>
<ListBox ItemTemplate="{StaticResource ListBoxItemTemplate}"
ItemSource="{Binding Collection}"/>
<Slider x:Name="slider1" Value="100" Maximum="250" Grid.Row="1"/>
</Grid>
If you know the sizes to which you'll be resizing, you could define a number of different ItemTemplates and switch bewteen them.

Resources