How to bind to an element inside a ControlTemplate? - wpf

I've created two custom controls in wpf, Control_A and Control_B. Both of them define a ColorProperty. Control_A's ControlTemplate consists of a Control_B instance,
<ControlTemplate
TargetType="{x:Type Control_A}">
<Border
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Control_B />
</Border>
</ControlTemplate>
What I want is to bind A.Color (target) to B.Color (source). How can this be achieved in XAML?

It can be done with a TwoWay binding. This way has it's dissadvantages but it works,
<ControlTemplate
TargetType="{x:Type Control_A}">
<Border
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Control_B
Color="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Color,
Mode=TwoWay}"/>
</Border>
</ControlTemplate>

I would try to give Control_B a Name and bind to its color.
Color="{Binding ElementName=Foo, Path=Color}"

Related

DisplayMemberPath not working for ListBox with custom ListBoxItem control

I've configured ListBox to use custom ControlTemplate for it self and custom ControlTemplate for ListBoxItem. Unfortunately such change disables the default behvaiour of DisplayMemberPath property.
// resource dictionary of ListBox control template
<ControlTemplate x:Key="CustomListBox" TargetType="ListBox" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:s="clr-namespace:System;assembly=mscorlib">
<Border CornerRadius="3" BorderThickness="{TemplateBinding Border.BorderThickness}" Padding="1,1,1,1" BorderBrush="{TemplateBinding Border.BorderBrush}" Background="{TemplateBinding Panel.Background}" Name="Bd" SnapsToDevicePixels="True">
<ScrollViewer Padding="{TemplateBinding Control.Padding}" Focusable="False">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
</ScrollViewer>
</Border>
</ControlTemplate>
//trigger code omitted
<Style TargetType="ListBox">
<Setter Property="Control.Template" Value="{StaticResource CustomListBox}"></Setter>
</Style>
// resource dictionary of ListBoxItem control template
<ControlTemplate x:Key="CustomListBoxItem" TargetType="ListBoxItem" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel>
<Border BorderThickness="0" CornerRadius="3" Padding="6 6" BorderBrush="{TemplateBinding Border.BorderBrush}" Background="White" Name="Bd" SnapsToDevicePixels="True">
<ContentPresenter Content="{TemplateBinding ContentControl.Content}" ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}" ContentStringFormat="{TemplateBinding ContentControl.ContentStringFormat}" HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding Control.VerticalContentAlignment}" SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
</Border>
<Label Height="3"></Label>
</StackPanel>
</ControlTemplate>
// trigger code omitted
<Style TargetType="ListBoxItem">
<Setter Property="Control.Template" Value="{StaticResource CustomListBoxItem}"></Setter>
<Setter Property="ItemsControl.DisplayMemberPath" Value="MatchText"></Setter>
</Style>
XAML
<ListBox x:Name="listBox" DisplayMemberPath="MyCustomText">
The DataContext of listBox is set using code. If I omit setting CustomListBoxItem as the control template, than it works as expected. How do you enable DisplayMemberPath when using custom control templates for ListBox and ListBoxItem?

Scrollable set of elements in WPF

I have a set of items in ItemsControl. I am displaying all of them but I want to make visible only a subset of items. So I kind of want to specify the visible area of ItemsControl (or any other element which supports this). Other elements could be seen after scrolling is applied.
I could do it on ViewModel-side and pass to ItemsControl only visible elements but I am interested in View-only solution. Is there any?
You can add a ScrollViewer in your ItemsControl's style, then if your items will overflow the width or height of the ItemsControl a ScrollBar will appear.
<Style x:Key="ItemsControlStyle1" TargetType="{x:Type ItemsControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ItemsControl}">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

WPF: ItemsControl's border not visible

I followed the instruction in this blog to add ScrollIntoView to ItemsControl.
But this makes the border invisible:
<ItemsControl BorderBrush="Black"
BorderThickness="3">
<ItemsControl.Template>
<ControlTemplate>
<ScrollViewer Padding="{TemplateBinding Padding}">
<ItemsPresenter />
</ScrollViewer>
</ControlTemplate>
</ItemsControl.Template>
<TextBlock Text="Test" />
<TextBlock Text="Test" />
<TextBlock Text="Test" />
</ItemsControl>
In order to display the border, I have to remove:
<ItemsControl.Template>
<ControlTemplate>
<ScrollViewer Padding="{TemplateBinding Padding}">
<ItemsPresenter />
</ScrollViewer>
</ControlTemplate>
</ItemsControl.Template>
But this way I won't be able to use the ScrollIntoView method.
Any ideas? Thanks
You need to include the border in the template.
<ControlTemplate>
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ScrollViewer Padding="{TemplateBinding Padding}">
<ItemsPresenter />
</ScrollViewer>
</Border>
</ControlTemplate>

wpf chart legend

How do I enlarge those rectangles ?
I'm using wpf toolkit charts and I've tried to play with the control legend but it didn't helped.
With Blend, in the Objects panel:
Right Click on [PieSeries]
-Edit Additional Templates
-Edit LegendItemStyle
-Edit a Copy
You should get a default style:
<Style x:Key="PieChartLegendItemStyle" TargetType="{x:Type chartingToolkit:LegendItem}">
<Setter Property="IsTabStop" Value="False" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type chartingToolkit:LegendItem}">
<Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
<StackPanel Orientation="Horizontal">
<Rectangle Width="8" Height="8" Fill="{Binding Background}" Stroke="{Binding BorderBrush}" StrokeThickness="1" Margin="0,0,3,0" />
<visualizationToolkit:Title Content="{TemplateBinding Content}" />
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And your control will get a LegendItemStyle
<Charting:PieSeries ItemsSource="{Binding PutYourBindingHere}"
IndependentValueBinding="{Binding Key}" DependentValueBinding="{Binding Value}" IsSelectionEnabled="True" LegendItemStyle="{DynamicResource PieChartLegendItemStyle}">

How can I reference an element inside a control template

Say I wanna put a CheckBox inside a Button. Is there anyway for me to reference that checkbox in code? i.e. In Window1.cs I want to write something like: testButton.innerCheckBox.DoStuff();
<ControlTemplate TargetType="{x:Type Button}">
<Microsoft_Windows_Themes:ButtonChrome SnapsToDevicePixels="true" x:Name="Chrome" BorderBrush="{TemplateBinding BorderBrush}" Fill="{TemplateBinding Background}" RenderDefaulted="{TemplateBinding IsDefaulted}" RenderMouseOver="{TemplateBinding IsMouseOver}" RenderPressed="{TemplateBinding IsPressed}" ThemeColor="NormalColor">
<Grid Width="32.083" Height="13.277">
<ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" HorizontalAlignment="Stretch" Margin="{TemplateBinding Padding}" VerticalAlignment="Stretch" RecognizesAccessKey="True" d:LayoutOverrides="Width, Height"/>
<CheckBox x:Name="innerCheckBox" HorizontalAlignment="Left" VerticalAlignment="Top" Content="CheckBox"/>
</Grid>
</Microsoft_Windows_Themes:ButtonChrome>
</ControlTemplate>
CheckBox innerCheckBox = testButton.Template.FindName("innerCheckBox", testButton) as CheckBox;

Resources