Access ControlTemplate components (windows 8 app) - wpf

I would like to combine some UI elements into a Control, and then access them by code. However I can't figure it out.
The control template:
<Page.Resources>
<Style x:Key="GridViewStyle1" TargetType="GridView">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="GridView">
<Grid>
<TextBox x:Name="theTextBox" Text="The Text" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Page.Resources>
And a reference to the Template:
<GridView x:Name="myGridView1" Style="{StaticResource TileControl}"/>
So what I'm looking for is something like this for example:
myGridView1.Style.Template.Gridview.theTextBox.Text
But I can't find it. Any idea how I can do that? Or maybe I'm on the wrong track since it shouldn't be so complicated?

To retrieve ControlTemplate-generated element you can use something like (after the template has been applied to the control)
yourcontrol.Template.FindName("ControlElementTemplateToFind")
See also msdn

Related

Expander.Content only applied to one

I am trying to apply style to multiple expanders which will have similar look and functionality. But the problem is that if I style Expander.Content only one of many will have content and the rest are all empty.
Minimal example:
<Style TargetType="Expander" BasedOn="{StaticResource {x:Type Expander}}">
<Setter Property="Header">
<Setter.Value>
Header
</Setter.Value>
</Setter>
<Setter Property="Content">
<Setter.Value>
<TextBlock Text="1"/>
</Setter.Value>
</Setter>
</Style>
<!-- .... -->
<Expander Grid.Row="0"/>
<Expander Grid.Row="1"/>
<Expander Grid.Row="2"/>
as you see only the second row has content (1) during design time. During run time only the last expander has content (1).
If I click on the first expander the content (1) from the third expander actually moved to the first expander.
Why is this happening? And how to fix it?
Styles only create one instance, which for visual elements can only be the child of a single parent. Set the ContentTemplate instead of the Content directly. (Templates just describe what is to be created by the control using it, so it can be shared.)

WPF subclass Control without adding logic, just to be able to customize style and template?

I'm searching for a good way to create style-able, reusable controls in WPF. For example, I've got a twitter feed that could look something like this (much simplified):
<ItemsControl ItemsSource={Binding tweets}>
<ItemsControl.DataTemplate>
<DataTemplate TargetType="tweet">
<StackPanel>
<Image Source="{Binding user.image}" />
<TextBlock Text="{Binding text}" />
</StackPanel>
</DataTemplate>
</ItemsControl.DataTemplate>
</ItemsControl>
To make this a reusable control, I could put this in a UserControl. But doing just that would make it impossible to change the way the image part is displayed for example.
So what I find myself doing now is creating a control for the user's image, like this:
public class UserImage : Control
{
// Empty class..
}
<Style TargetType="{x:Type UserImage}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type UserImage}">
<Image Source="{Binding}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
// The itemscontrol datatemplate now looks like this
<DataTemplate TargetType="tweet">
<StackPanel>
<UserImage DataContext="{Binding user.image}" />
<TextBlock Text="{Binding text}" />
</StackPanel>
</DataTemplate>
Now I could do something like this to customize the appearance of the user image:
<Style TargetType="{x:Type UserImage}" BasedOn="{StaticResource {x:Type UserImage}}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type UserImage}">
<Ellipse>
<Ellipse.Fill>
<ImageBrush ImageSource="{Binding}">
</Ellipse.Fill>
</Ellipse>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Even though this works, it does feel a bit inefficient and well ... wrong to have to create an "empty" control for each and every component in the custom control. Is this the way to go, or is there a cleaner way?

Create a visual template for grid

I am trying to create a visual template (saved in resource dictionary as xaml code) for a grid object, that I will apply to various grid objects created later in runtime.
I need a simple style with border and background.
What would be the best way of doing this?
Simple working examples would be greatly appreciated.
Ok, so, after searching for examples, I tried something like this:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="TestStyle">
<Setter Property="Background" Value="#FF873507" />
<Setter.Value>
<ControlTemplate>
<Grid>
<Border BorderThickness="7" CornerRadius="4">
<Border.BorderBrush>
<SolidColorBrush Color="#73B2F5"/>
</Border.BorderBrush>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Style>
</ResourceDictionary>
WPF doesn't really work like that... because the Grid class has no Template property, you cannot define a new ControlTemplate for it. The nearest thing that you can do is to create a UserControl with the UI elements that you want to use and then display the UserControl wherever you want to display those controls.
Alternatively, you could define your content inside a ControlTemplate if the inner controls will always be the same:
<ControlTemplate x:Key="StaticGrid">
<Grid>
<Border BorderThickness="7" CornerRadius="4">
<Border.BorderBrush>
<SolidColorBrush Color="#73B2F5"/>
</Border.BorderBrush>
<!--Add your inner elements here-->
</Border>
</Grid>
</ControlTemplate>
You could then display it like this:
<ContentControl Template="{StaticResource StaticGrid}" />
However, you wouldn't be able to add different inner elements using this method. If you used the UserControl method, you could potentially replace the word UserControl with Grid so that you were in fact extending the Grid class, but you still wouldn't be able to add different elements to it.
The best that you could do in a Style would be to set the Background property.
After more tries and frustrations, I found a much simpler solution, that worked for me.
Instead of trying to apply the style to the grid, I applied it to the border around the grid.
So, my dictionary looks like this:
<Style x:Key="TestStyle" TargetType="{x:Type Border}">
<Setter Property="Background" Value="#FFBDACA2" />
<Setter Property="BorderBrush" Value="#FFFF5E00" />
<Setter Property="CornerRadius" Value="30,30,30,30" />
<Setter Property="BorderThickness" Value="10" />
</Style>
And my main frame xaml:
<Border Style="{StaticResource TestStyle}" >
<Grid>
</Grid>
</Border>

Silverlight: Why doesn't this style work?

I'm using Silverlight 4. I have a button:
<Button Click="addTopicButton_Click">
<Image Source="/PlumPudding;component/Images/appbar.add.rest.png" />
</Button>
It looks fine. However, when I try to set its Content using a Style, no content appears:
<Style x:Name="AddButton" TargetType="Button">
<Setter Property="Content">
<Setter.Value>
<Image Source="/PlumPudding;component/Images/appbar.add.rest.png" />
</Setter.Value>
</Setter>
</Style>
<Button Click="addTopicButton_Click" Style="{StaticResource AddButton}" />
The button is empty. Why is this?
Its not a good idea to include UIElements such as Image in a style. Such an object is created only once when the style is put together during Xaml parsing. An important thing to understand about UIElements is that a single instance can only appear once in the Visual Tree. So even if your code worked it would only work for one button, any other button trying to use the same style would fail.
Instead you can use the ContentTemplate property like this:-
<Style x:Key="AddButton" TargetType="Button">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Image Source="/PlumPudding;component/Images/appbar.add.rest.png" />
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
<Button Click="addTopicButton_Click" Style="{StaticResource AddButton}" />
The button is now given a DataTemplate that it uses to construct the child element that renders the content of the button. Each button will therefore construct its own independent instance of an Image control.
You should use x:Key to name your Style element rather than x:Name
Your code requires two changes.
Changed x:Name to x:Key, And refer to it when you want to use it, using StaticResource.
Change this
<Setter.Value>
<Image Source="whatever..." />
</Setter.Value>
to this,
<Setter.Value>
<DataTemplate>
<Image Source="whatever..." />
</DataTemplate>
</Setter.Value>
See if it helps you!

WPF ControlTemplate with foreach?

I currently try to create classes for a paint-like WPF application. I have to base classes LineMovement (line from StartPoint to EndPoint) and PathMovement (line going through all points specified in a property Points of type PointCollection). These classes inherit from Control and get their looks through a ControlTemplate.
Now I want to add (what I call) PointMovers to the ControlTemplate. These should be little visual elements residing on each of the points in either of the Movement classes. They should become a kind of grip mechanism to drag the underlying point around.
The problem is of course that I don't know a way to create a variable number of elements in a ControlTemplate. It would be cool if I could do something like this:
<Style x:Key="{x:Type mov:PathMovement}" TargetType="{x:Type mov:PathMovement}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type mov:PathMovement}">
<Grid>
<Polyline Points="{TemplateBinding Points}" />
<!-- interesting part start -->
<foreach loopvariable="Point" in="{TemplateBinding Points}">
<PointMover Point="Point" />
</foreach>
<!-- interesting part end -->
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Is this possible? Do you have another approach in mind that could work?
Thanks in advance!
Use an ItemsControl in conjunction with an ItemTemplate:
<ItemsControl ItemsSource="{Binding Points}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<!-- rendered for each point -->
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
By the sounds of your use case, you may also want to read up on AdornerLayers.

Resources