WPF XAML binding properties within a ControlTemplate - c#

I'm trying to create a ControlTemplate representing a Slider and a TextBox (and a Label), where the text of the TextBox should show the value of the Slider.
I can't figure out how to correctly setup the binding between the Slider's Value property and the TextBox' Text property.
This is my ControlTemplate:
<ControlTemplate x:Key="myslider" TargetType="Slider">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
<Label>Slider</Label>
<Slider
Width="100"
Minimum="0" Maximum="100"/>
<TextBox Width="40"
Text="{Binding RelativeSource={RelativeSource TemplatedParent},
Path=Value}">
</TextBox>
</StackPanel>
</ControlTemplate>
Here I instantiate 3 Slider using the ControlTemplate:
<StackPanel>
<Slider Template="{StaticResource myslider}"></Slider>
<Slider Template="{StaticResource myslider}"></Slider>
<Slider Template="{StaticResource myslider}"></Slider>
</StackPanel>
This ends up looking like this:
The goal is that each slider controls the value within the indivual TextBoxes.

I would prefer using a User Control as a first choice. But if we follow your line of thought the shared value of the Slider and the TextBox should be the Value dependency property on the parent Slider.
The tested code is as following :
<Window.Resources>
<ControlTemplate x:Key="myslider" TargetType="Slider">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
<Label>Slider</Label>
<Slider
Value="{Binding RelativeSource={RelativeSource TemplatedParent},Path=Value,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged,Delay=10}"
Minimum="{Binding RelativeSource={RelativeSource TemplatedParent},Path=Minimum,Mode=OneWay}"
Maximum="{Binding RelativeSource={RelativeSource TemplatedParent},Path=Maximum,Mode=OneWay}"
Width="100"
/>
<TextBox Width="100"
Text="{Binding RelativeSource={RelativeSource TemplatedParent},
Path=Value,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged,Delay=10}">
</TextBox>
</StackPanel>
</ControlTemplate>
</Window.Resources>
<Grid>
<StackPanel Orientation="Vertical">
<Slider Template="{StaticResource myslider}" Minimum="0" Maximum="100"></Slider>
<Slider Template="{StaticResource myslider}" Minimum="0" Maximum="100"></Slider>
<Slider Template="{StaticResource myslider}" Minimum="0" Maximum="100"></Slider>
</StackPanel>
</Grid>

Related

WPF Adding a datatrigger to the ImageSource of a user control from another control

I have the following usercontrol:
<Border
Style="{StaticResource notificationBarBorderStyle}"
Height="21"
>
<StackPanel
Orientation="Horizontal"
Style="{StaticResource notificationBarStyle}"
>
<DockPanel>
<Image
Width="17"
Height="16"
Margin="4,0,11,0"
Source="{Binding ElementName=NotificationControl, Path=ImageSource}"
/>
<TextBlock
x:Name="notificationTextBlock"
VerticalAlignment="Center"
Style="{StaticResource textBlockStyle}"
Text="{Binding ElementName=NotificationControl, Path=Message}"
/>
</DockPanel>
</StackPanel>
</Border>
and then in another usercontrol i try to reference it like so:
<Controls:NotificationBarControl
Grid.Row="2"
Grid.Column="0"
DataContext="{Binding IncomingResult}"
Message="{Binding TaskResultsMessage}"
Visibility="{Binding Path=ShowTaskResults, Converter={StaticResource boolToHiddenVisibilityConverter}}"
Command="{Binding DisplayTaskError}"
ImageSource="{DynamicResource somePicture1}"
>
I want to be able to put a data trigger on the image source so that depending on the state of a boolean flag, a different image will appear (call it somePicture2). I do not really want to do much to change the control itself, as it is referenced a few times in a rather large project and I do not want to break anything.
You could set the Style property of the control to a Style with a DataTrigger that binds to your bool property:
<Controls:NotificationBarControl
Grid.Row="2"
Grid.Column="0"
DataContext="{Binding IncomingResult}"
Message="{Binding TaskResultsMessage}"
Visibility="{Binding Path=ShowTaskResults, Converter={StaticResource boolToHiddenVisibilityConverter}}"
Command="{Binding DisplayTaskError}">
<Controls:NotificationBarControl.Style>
<Style TargetType="Controls:NotificationBarControl">
<Setter Property="ImageSource" Value="{StaticResource somePicture1}" />
<Style.Triggers>
<DataTrigger Binding="{Binding YourBooleanSourceProperty}" Value="True">
<Setter Property="ImageSource" Value="{StaticResource somePicture2}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Controls:NotificationBarControl.Style>
</Controls:NotificationBarControl>

WPF TextBlock not displaying underscore

I have this block of code in a dropdown control:
<ComboBox.Template>
<ControlTemplate TargetType="ComboBox">
<Grid>
<ToggleButton x:Name="ToggleButton"
Grid.Column="2" IsChecked="{Binding Path=IsDropDownOpen,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}"
Focusable="false"
ClickMode="Press"
HorizontalContentAlignment="Left" >
<ToggleButton.Template>
<ControlTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="18"/>
</Grid.ColumnDefinitions>
. . . .
<Border x:Name="BorderComp"
Grid.Column="0"
CornerRadius="0"
Margin="1"
Background="{DynamicResource {x:Static SystemColors.ControlLightBrushKey}}"
BorderBrush="{DynamicResource {x:Static SystemColors.ControlDarkBrushKey}}" BorderThickness="0,0,0,0" >
<TextBlock Text="{Binding Path=Text,RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}"
Background="{DynamicResource {x:Static SystemColors.ControlLightBrushKey}}"
Padding="2" />
</Border>
When the text to display contains an underscore, the underscore is not displayed on screen. I use Snoop to check the values and the Text value does contain the underscore. For instance, X_9999 is displayed as X9999.
I find a number of postings explaining that underscores are used as an accelerator on Labels, but this is not supposed to affect TextBlock.
Any ideas?
UPDATE
I found the issue to be within the ComboBox.ItemTemplate which was defined as follows:
<ComboBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Title}"
IsChecked="{Binding Path=IsSelected, Mode=TwoWay}"
Tag="{RelativeSource FindAncestor, AncestorType={x:Type ComboBox}}"
Click="CheckBox_Click" />
</CheckBox>
</DataTemplate>
</ComboBox.ItemTemplate>
I changed to the following and everything works correctly now. Apparently Checkbox uses a Label by default.
<ComboBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding Path=IsSelected, Mode=TwoWay}"
Tag="{RelativeSource FindAncestor, AncestorType={x:Type ComboBox}}"
Click="CheckBox_Click">
<TextBlock Text="{Binding Title}" />
</CheckBox>
</DataTemplate>
</ComboBox.ItemTemplate>

Expanding ListView and Clickable image

I have two questions.
Q1: I have a ListView and I want OnSelectedItem to expand the attributes and show more attributes. Is this possible? How? [I have the attributes in the ObservableCollection]
Q2: I want to put a clickable image inside the view, that will change ViewModel (chat behavior). Is this possible? How?
ListView
<ListView x:Name="dataGrid" ItemsSource="{Binding Friends}" Height="314" BorderThickness="0" SelectedItem="{Binding SelectedItemFriends}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="Resources\Images\ic_status.png" Height="24" Width="18"/>
<StackPanel Margin="5" Orientation="Vertical">
<TextBlock FontWeight="Bold" Text="{Binding name}"/>
<TextBlock Text="{Binding lastLocation}"/>
<TextBlock Text="{Binding timestamp}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
A1: In datatemplate, create how you would like the extended attributes to appear and place them in a container such as a stack panel.
Then use an DataTrigger using the IsSelected property to change the visibility of the stack panel container from visible and collapsed as needed.
A2: The easiest way would be to use a Button with the content source set to an image as this will give you the click event/command binding to play with.
EDIT: Example of the first answer could look like:
<ListView x:Name="dataGrid" Height="314" BorderThickness="0" SelectedItem="{Binding SelectedItemFriends}" ItemsSource="{Binding Friends}" >
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" >
<Image Source="Resources\Images\ic_status.jpg" Height="24" Width="18"/>
<StackPanel Margin="5" Orientation="Vertical">
<TextBlock FontWeight="Bold" Text="{Binding Name}"/>
<StackPanel x:Name="AdditionItems" Orientation="Vertical" Visibility="Collapsed">
<TextBlock Text="{Binding LastLocation}"/>
<TextBlock Text="{Binding TimeStamp}"/>
</StackPanel>
</StackPanel>
</StackPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListViewItem}}, Path=IsSelected}" Value="true">
<Setter TargetName="AdditionItems" Property="Visibility" Value="Visible"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I have run this code and it works for me, it should be enough to put you on the right track. The important things to note are that the trigger is attached to the ListViewItem, it will trigger when it the IsSelected property turns true, it will then change the visibility of the StackPanel called "Additional Items" to visible from collapsed.

How to access dynamic control WPF in DataTemplate

I created a tabcontrol with TabItem dynamic, and each TabItem with a button to close it, but just want that button visible when the TabItem is selected.
But I can not access the control inside the DataTemplate
<TabControl Name="dynamicTab" ItemsSource="{Binding}" Margin="0,85,0,0">
<TabControl.Resources>
<DataTemplate x:Key="TabHeader" DataType="TabItem">
<DockPanel>
<Button
Focusable="False"
BorderThickness="0"
Background="Transparent"
BorderBrush="Transparent"
Padding="-4"
Height="10"
Width="10"
Name="btnDelete" Visibility="Hidden" DockPanel.Dock="Right" Margin="5,0,0,0" Click="btnDelete_Click"
CommandParameter="{Binding RelativeSource={RelativeSource AncestorType={x:Type TabItem}}, Path=Name}">
<Image Name="imgButtonClose" Source="/Recursos;component/Imagens/close16x16.png" Height="10" Width="10"/>
</Button>
<TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type TabItem}}, Path=Header}" />
</DockPanel>
</DataTemplate>
</TabControl.Resources>
</TabControl>
Just use the binding on the IsSelected property of ancestoral TabItem:
<BooleanToVisibilityConverter x:Key="boolToVisibilityConverter"/>
...
<Button ...
Name="btnDelete"
Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type TabItem}}, Path=IsSelected, Converter={StaticResource boolToVisibilityConverter}">
...
</Button>
If you have no problems with this binding:
CommandParameter="{Binding RelativeSource={RelativeSource AncestorType={x:Type TabItem}}, Path=Name}"
then the proposed code should work.

Alternative of ContentPresenter with selected item in wpf

Are any controls or kind of, with selectedindexchanged event or property selecteditem maybe?
I use ContentPresenter now and me need some solution for getting index of selected item issue. With DataTemplate inside, it's desirable.
My code looks:
<Border BorderThickness="1">
<ContentPresenter Content="{Binding Path=Value}">
<ContentPresenter.Resources>
<DataTemplate DataType="{x:Type System:String}">
<TextBox Text="{Binding Path=Content, RelativeSource={RelativeSource AncestorType={x:Type ContentPresenter}}}"
TextAlignment="Left"
BorderThickness="0"/>
</DataTemplate>
<DataTemplate DataType="{x:Type System:Int32}">
<TextBox Text="{Binding Path=Content, RelativeSource={RelativeSource AncestorType={x:Type ContentPresenter}}}"
TextAlignment="Left"
BorderThickness="0"/>
</DataTemplate>
<DataTemplate DataType="{x:Type System:Double}">
<TextBox Text="{Binding Path=Content, RelativeSource={RelativeSource AncestorType={x:Type ContentPresenter}}}"
TextAlignment="Left"
BorderThickness="0"/>
</DataTemplate>
<DataTemplate DataType="{x:Type System:Boolean}">
<Border Background="White">
<CheckBox IsChecked="{Binding Path=Content, RelativeSource={RelativeSource AncestorType={x:Type ContentPresenter}}}"
HorizontalAlignment="Left"/>
</Border>
</DataTemplate>
</ContentPresenter.Resources>
</ContentPresenter>
</Border>
You need an ItemsControl or its derivates ListView, ListBox, DataGrid etc. They have SelectedItem property on them.
In order to set the ItemTemplate depending on the any criteria, use DataTemplateSelector and set Itemscontrol.Itemtemplateselector property. Details at msdn
http://msdn.microsoft.com/en-us/library/system.windows.controls.itemscontrol.itemtemplateselector(v=vs.110).aspx

Categories