WPF - can't access template elements for objects created at runtime - c#

I'm trying to create a checkable variation of the ComboBox control using a custom ControlTemplate. The eventual aim is to add a click handler for the integrated CheckBox every time a new ComboBoxItem is created - but when I use (CheckBox)template.FindName("myCheckBox", item); it always returns null.
Here is the Style that sets the ControlTemplate:
<Style x:Key="CheckedComboBoxStyle" TargetType="{x:Type ComboBox}">
<Setter Property="Margin" Value="8"></Setter>
<Setter Property="Background" Value="Transparent"></Setter>
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="{x:Type ComboBoxItem}">
<Setter Property="Margin" Value="2" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBoxItem}">
<StackPanel x:Name="myStackPanel" Orientation="Horizontal">
<CheckBox x:Name="myCheckBox" Focusable="False" Width="50" Foreground="{StaticResource textBrush}"
IsChecked="{Binding Path=IsChecked, Mode=TwoWay,
RelativeSource={RelativeSource TemplatedParent}}">
<ContentPresenter></ContentPresenter>
</CheckBox>
<TextBlock x:Name="myTextBlock" Text="{Binding Name}" Width="100" />
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
</Style>
and here is the code that tries to get a reference to the CheckBox in the code behind whenever a new item is added to the ComboBox:
ComboBoxItem item = new ComboBoxItem();
item.Content = system.Name;
item.Tag = system.Id;
cbSystems.Items.Add(item);
item.Loaded += (sender, e) =>
{
var template = item.Template;
CheckBox chkBox = (CheckBox)template.FindName("myCheckBox", item);
MessageBox.Show(chkBox.Name);
};

Related

How can I change background behind border (ListView.ItemTemplete->datatemplete) when I hover or click?

My problem is when I click or hover in ListViewItem which also show the silver background:
enter image description here
this is my code xaml:
<ListView
Margin="0,30,0,0"
Height="600"
ScrollViewer.VerticalScrollBarVisibility="Hidden"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
Name="ListViewFC" ItemsSource="{Binding ListWords, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
SelectedItem="{Binding SelectedItem, Mode=TwoWay}" >
<ListView.ItemTemplate>
<DataTemplate>
<Border
Width="340"
x:Name="Border"
Height="80"
Background="Pink"
CornerRadius="15"
BorderThickness="1"
>
<Grid>
<TextBlock
VerticalAlignment="Center"
x:Name="txtContent"
Foreground="Black"
Text="{Binding Question1,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}"
TextWrapping="NoWrap"
Margin="30 0 0 0"
FontSize="15"
/>
</Grid>
</Border>
<DataTemplate.Triggers>
<DataTrigger
Binding="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type ListViewItem}}, Path=IsSelected}" Value="True">
<Setter TargetName="Border" Property="Background" Value="White" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I want that When I hover or click It don't show the silver background.
pls, help me .Thanks.
Add this inside your ListView:
<ListView.Resources>
<Style BasedOn="{StaticResource TextBlockStyle}" TargetType="{x:Type TextBlock}" />
<Style BasedOn="{StaticResource ListViewItemStyle}" TargetType="{x:Type ListViewItem}" />
</ListView.Resources>
Then add this outside of your ListView (this displays a background of gold on hover):
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Gold" />
</Trigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
The default ControlTemplate of the ListView contains a Border with Padding of 2X. Hence you have to change its template something like this
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<ContentPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>

Wpf TreeView With CheckBox

I need to add "Select All" to my wpf application ,
I've tried to do a simple binding but it doesn't work .
Can Someone Please advise , performing a simple binding
or other strait forward solution ?
Here's my treeview xaml :
<TreeView Name="CurrentTreeView" Margin="5" BorderBrush="Transparent" BorderThickness="0"
ScrollViewer.VerticalScrollBarVisibility="Auto">
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<Setter Property="IsSelected" Value="{Binding IsSelected}" />
<Setter Property="IsExpanded" Value="{Binding IsExpanded}" />
<Setter Property="HeaderTemplate" >
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox
Focusable="False"
Checked="CheckedItemCurreuntSession"
Unchecked="UnCheckedItemCurreuntSession"
Name="treeChk"
Tag="{Binding Path=ChName}"
Style="{StaticResource CheckBoxStyle1}"
IsChecked="{Binding Path=IsChecked}"
VerticalAlignment="Center"/>
<TextBlock VerticalAlignment="Center" Text="{Binding}"
Margin="5"
TextOptions.TextFormattingMode="Display"
TextOptions.TextHintingMode="Auto"
/>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
<Style x:Key="CheckBoxListStyle" TargetType="{x:Type ListBox}">
<Setter Property="SelectionMode" Value="Multiple"/>
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Margin" Value="2"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<CheckBox Focusable="False" IsChecked="{Binding Path=IsSelected, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent} }">
<ContentPresenter/>
</CheckBox>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
</Style>

Bind textBox's control text to class property

I have a diagram designer, in which every figure should have editable sign on it. This is how the programm looks like.
As you can see, the textbox with default text appears, but I cant figure out how to save the text input to corresponding "Text" property of DesignerItem class object. DesignerItem.xaml as follows:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="clr-namespace:WPFCanvas"
xmlns:c="clr-namespace:WPFCanvas.Controls">
<ContextMenu x:Key="DesignerItemContextMenu">
...
</ContextMenu>
<!-- Connector Style -->
<Style TargetType="{x:Type s:Connector}">
...
</Style>
<!-- ConnectorDecoratorTemplate Default Template -->
<ControlTemplate x:Key="ConnectorDecoratorTemplate" TargetType="{x:Type Control}">
...
</ControlTemplate>
<!-- ResizeDecorator Default Template -->
<ControlTemplate x:Key="ResizeDecoratorTemplate" TargetType="{x:Type Control}">
...
</ControlTemplate>
<!-- DragThumb Default Template -->
<Style TargetType="{x:Type c:DragThumb}">
...
</Style>
<!-- TextBoxDecorator Default Template -->
<ControlTemplate x:Key="TextBoxDecoratorTemplate" TargetType="{x:Type Control}">
<ContentControl Width="Auto" Height="Auto" VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBox FontSize="11" Margin="1,1,0,0" TextWrapping="Wrap" AcceptsReturn="True"
Background="Transparent" Text="Lorem ipsum dolor sit amet, consectetuer adipiscing elit."/>
</ContentControl>
</ControlTemplate>
<!-- DesignerItem Style -->
<Style TargetType="{x:Type s:DesignerItem}">
<Setter Property="MinWidth" Value="25"/>
<Setter Property="MinHeight" Value="25"/>
<Setter Property="SnapsToDevicePixels" Value="True"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type s:DesignerItem}">
<Grid DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}"
ContextMenu="{StaticResource DesignerItemContextMenu}">
<!-- DragThumb -->
<c:DragThumb x:Name="DragThumb" Cursor="SizeAll"/>
<!-- ResizeDecorator -->
<Control x:Name="ResizeDecorator"
Visibility="Collapsed"
Template="{StaticResource ResizeDecoratorTemplate}"/>
<!-- ContentPresenter -->
<ContentPresenter x:Name="ContentPresenter"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Content="{TemplateBinding ContentControl.Content}"
Margin="{TemplateBinding ContentControl.Padding}"/>
<!-- ConnectorDecorator -->
<Control x:Name="ConnectorDecorator"
Visibility="Hidden"
Template="{StaticResource ConnectorDecoratorTemplate}"/>
<!-- TextBoxDecorator -->
<Control x:Name="TextBoxDecorator"
Template="{StaticResource TextBoxDecoratorTemplate}"/>
</Grid>
<ControlTemplate.Triggers>
<DataTrigger Value="True" Binding="{Binding RelativeSource={RelativeSource Self},Path=Text}">
<Setter TargetName="TextBoxDecorator" Property="Visibility" Value="Visible"/>
</DataTrigger>
<Trigger Property="Text" Value="true">
<Setter TargetName="TextBoxDecorator" Property="Visibility" Value="Visible"/>
</Trigger>
<DataTrigger Value="True" Binding="{Binding RelativeSource={RelativeSource Self},Path=IsSelected}">
<Setter TargetName="ResizeDecorator" Property="Visibility" Value="Visible"/>
</DataTrigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="ConnectorDecorator" Property="Visibility" Value="Visible"/>
</Trigger>
<DataTrigger Value="True" Binding="{Binding RelativeSource={RelativeSource Self},Path=IsDragConnectionOver}">
<Setter TargetName="ConnectorDecorator" Property="Visibility" Value="Visible"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And the DesignerItem.cs (without unnecessary code as well):
//These attributes identify the types of the named parts that are used for templating
[TemplatePart(Name = "DragThumb", Type = typeof(DragThumb))]
[TemplatePart(Name = "ResizeDecorator", Type = typeof(Control))]
[TemplatePart(Name = "ConnectorDecorator", Type = typeof(Control))]
[TemplatePart(Name = "ContentPresenter", Type = typeof(ContentPresenter))]
public class DesignerItem : ContentControl, ISelectable, IGroupable
{
public bool IsSelected
{
get { return (bool)GetValue(IsSelectedProperty); }
set { SetValue(IsSelectedProperty, value); }
}
public static readonly DependencyProperty IsSelectedProperty =
DependencyProperty.Register("IsSelected", typeof(bool),
typeof(DesignerItem),
new FrameworkPropertyMetadata(false));
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string),
typeof(DesignerItem));
}
In order to save the text from the visual TextBox to the DesignerItem.Text property, a Binding is needed. The binding target is the TextBox inside the TextBoxDecoratorTemplate and the binding source is the DesignerItem.Text property.
Since you assign the DesignerItem instance as your DataContext (<Grid DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}" .../>), the binding can directly target the Text property of the DataContext contents.
<!-- TextBoxDecorator Default Template -->
<ControlTemplate x:Key="TextBoxDecoratorTemplate" TargetType="{x:Type Control}">
<ContentControl Width="Auto" Height="Auto" VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBox FontSize="11" Margin="1,1,0,0" TextWrapping="Wrap" AcceptsReturn="True"
Background="Transparent" Text="{Binding Text}"/>
</ContentControl>
</ControlTemplate>
A little side note:
Your ControlTemplate.Triggers look like they need some changes. You are triggering a string property against Value="True", which will only trigger when the text contains the string "True". I feel like the idea was more like triggering on something else.

Filtering a ComboBox with a GroupStyle

I have a Telerik ComboBox which has a GroupStyle applied to it. I want to have it so that when the items are filtered, the group items disappear if they have no children items, and it continues up the hierarchy.
So, this is the initial setup:
Current:
Desired:
For reference:
GroupItem Style
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Expander Header="{Binding Path=Name}">
<ItemsPresenter Margin="20,0,0,0" />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger
Binding="{Binding Path=Name}"
Value="{x:Null}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<ItemsPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
RadComboBox
<telerik:RadComboBox
Grid.Column="1"
DisplayMemberPath="Name"
IsEditable="True"
IsFilteringEnabled="True"
ItemsSource="{Binding Path=Analyzers}"
KeyboardNavigation.TabNavigation="Local"
OpenDropDownOnFocus="True"
SelectedItem="{Binding Path=Analyzer, Mode=OneWayToSource}"
SelectedValue="{Binding Path=AnalyzerId, Converter={utilities:NullToZeroValueConverter}}"
SelectedValuePath="Id"
Style="{StaticResource ResourceKey=RadComboBoxStyle.CanDisable}"
TabIndex="2">
<telerik:RadComboBox.ItemContainerStyle>
<Style
BasedOn="{StaticResource ResourceKey=RadComboBoxItemStyle}"
TargetType="telerik:RadComboBoxItem">
<Setter Property="ToolTip" Value="{Binding Path=Description}" />
</Style>
</telerik:RadComboBox.ItemContainerStyle>
<telerik:RadComboBox.GroupStyle>
<GroupStyle />
</telerik:RadComboBox.GroupStyle>
</telerik:RadComboBox>
I found the following (related) example on the Telerik forums.
Example

WPF Propagating GotFocus over the visualtree

I Have this Style template
<Style x:Key="placeHolder" TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Grid>
<TextBox Text="{Binding Path=Text,
RelativeSource={RelativeSource TemplatedParent},
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}"
x:Name="textSource"
Background="Transparent"
Focusable="True"
Panel.ZIndex="2">
</TextBox>
<TextBox Text="{TemplateBinding Tag}" Background="{TemplateBinding Background}" Panel.ZIndex="1">
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Foreground" Value="Transparent"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Text, Source={x:Reference textSource}}" Value="">
<Setter Property="Foreground" Value="LightGray"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And In a Custom Control have a fiel that uses this template:
<TextBox x:Name="DatoABuscar"
Height="Auto"
MinHeight="25"
Text="{Binding Filtro,UpdateSourceTrigger=PropertyChanged}"
Margin="1,1,1,0"
PreviewKeyDown="DatoABuscar_PreviewKeyDown"
VerticalAlignment="Center"
Style="{StaticResource placeHolder}"
Tag="{x:Static resources:Labels.CONTROLES_SearchPlaceHoderText}"
GotFocus="DatoABuscar_GotFocus"/>
As you cold see I have a GotFocus handler with this code:
private void DatoABuscar_GotFocus(object sender, RoutedEventArgs e)
{
((TextBox)sender).SelectAll();
}
This handle Works perfect and I pretend to select all the content of the textbox when GotFocus Happens, but If I understand the real textbox showed after GotFocus happen is textSource inner into the style template.
Now My Questions are?
How can I do to propagate the got focus received by DatoAbuscar to textSource?
or
How can i do to Access the visualtree under the DatoABuscar to get textSource?
or
How can i do to Select all text in textSource when DatoAbuscar recieves the GotFocus**?
Another aproach ?
EDIT: I'm totally wrong the problem isn't the TexBox where I'm selecting the text. My problema was the method to select the text. Finally I Implement This Post
Actually you only need to use FindName to find the "textSource".
private void DatoABuscar_GotFocus(object sender, RoutedEventArgs e)
{
var txt = sender as TextBox;
var innerTxt = txt.Template.FindName("textSource", txt) as TextBox;
Keyboard.Focus(innerTxt);
innerTxt.SelectAll();
}

Categories