FocusElement does not change focus when I set it using a DataTrigger - wpf

I am making a window that shows the user multiple options, with each a radiobutton and a textbox.
When opening this window, the focus should be on the textbox corresponding to the radiobutton that is checked when opening the window (this is all preset, no need to worry about this).
It is important that it gets fixed either in xaml or in the code-behind.
I have used a DataTrigger to change the FocusedElement to the right textbox, however it gets overwritten after it is set.
The relevant code is in the DataTrigger below. The color gets changed correctly, however the FocusElement does not.
I have tried all the options that I have found on stackoverflow and google. The issue does not lie in the DataTrigger or the setting of the FocusedElement. I think it lies in the fact that it gets overridden at the end. I have used Snoop to see the changes in the Keyboard.FocusedElement and it does not show any change.
<DataTemplate x:Uid="DataTemplate_1" >
<RadioButton x:Uid="RadioButton_1" GroupName="Options" IsChecked="{Binding IsSelected}" Margin="4,0,0,0" Name="RadioBtn">
<StackPanel x:Uid="StackPanel_1" Orientation="Horizontal" >
<Label x:Uid="Label_1" Visibility="{Binding IsUserInput, Converter={cs:OppositeVisibilityConverter}}" Content="{Binding Description, Mode=OneWay}" />
<Label x:Uid="Label_2" Visibility="{Binding IsUserInput, Converter={cs:VisibilityConverter}}" Content="Anders, nl: " />
<TextBox x:Uid="MemAnders" Visibility="{Binding IsUserInput, Converter={cs:VisibilityConverter}}" Text="{Binding AlternativeText}"
Name="MemAnders" MinWidth="400" IsTabStop="False"
>
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected}" Value="True">
<Setter Property="FocusManager.FocusedElement" Value="{Binding ElementName=MemAnders}"/>
<Setter Property="Background" Value="LightGoldenrodYellow" />
</DataTrigger>
<DataTrigger Binding="{Binding IsSelected}" Value="False">
<Setter Property="FocusManager.FocusedElement" Value="{Binding ElementName=RadioBtn}"/>
<Setter Property="Background" Value="LightBlue" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</StackPanel >
</RadioButton >
</DataTemplate >
The textbox corresponding to the checked radiobutton should be focused. Instead another (parent?) object is focused.
Anyone know a workaround for this?

The work-around turned out to be setting focus to the textbox in the Window_Loaded function.
I used an algorithm provided by Find a WPF element inside DataTemplate in the code-behind to find the correct textbox element. Then I did TextBox.Focus(); and that fixed it.

Related

focus is wrong when trying to click inside a RadComboBox

So i have a RadCombobBox which is heavilly edited to have a list of options where 1 of the options can be an input field. There are different types of input fields you can chose from but i'm having a problem with the integer input field. There's also one with a text input field which shows no problems.
The combobox looks like this:
The text is dutch (don't mind it) beneath the text options there is a preset value, the idea here is you can either choose a preset setting (which corresponds to an integer value) or you can type in your own value.
What happens when i try to click on different places (last one is very peculiar):
If i try to click on the input box (which is highlighted in gray) it selects it and closes the combo box (this is not what i want).
If i try to click on the arrows on the right side of the combobox it changes the value.
If i scroll with my mouse, it changes the value.
If i keep my mouse down on the input box i can actually type in the value i want.
If i first click on the buttons on the side and then click inside the input box i can edit the value.
What I want is to click on the input box and be able to edit the value inside and when i'm finished press enter (or outside the combobox) to close it.
Somehow the focus or, something (i am not 100% sure) just seems to fail me.
here is the xaml code for the IntegerDataTemplate:
Integer selector
<Style x:Key="NumericUpDownStyle" TargetType="{x:Type telerik:RadNumericUpDown}">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="BorderBrush" Value="{StaticResource AccentBrush}" />
</Trigger>
<Trigger Property="IsEditable" Value="False">
<Setter Property="SmallChange" Value="0" />
<Setter Property="LargeChange" Value="0" />
</Trigger>
</Style.Triggers>
</Style>
<!-- Integer editor -->
<DataTemplate x:Key="IntegerDataTemplate">
<telerik:RadNumericUpDown x:Name="NumericUpDown"
Width="{Binding Path=ActualWidth,
ElementName=Editor}"
MaxWidth="{Binding Path=ActualWidth,
ElementName=Editor,
Converter={StaticResource WidthToWidthConverter}}"
HorizontalContentAlignment="Left"
Background="Transparent"
FontFamily="{telerik:Windows8Resource ResourceKey=FontFamilyStrong}"
IsInteger="True"
Style="{StaticResource NumericUpDownStyle}"
UpdateValueEvent="PropertyChanged"
Value="{Binding Path=Value,
UpdateSourceTrigger=PropertyChanged,
NotifyOnSourceUpdated=True}">
<telerik:RadNumericUpDown.NumberFormatInfo>
<globalization:NumberFormatInfo NumberGroupSeparator="" />
</telerik:RadNumericUpDown.NumberFormatInfo>
</telerik:RadNumericUpDown>
</DataTemplate>
<!-- Integer as Option -->
<DataTemplate x:Key="OptionsDataTemplate">
<TextBlock Height="20" Text="{Binding Converter={StaticResource IntegerSelectorObjectToStringConverter}}" />
</DataTemplate>
<local:SelectorTypeTemplateSelector x:Key="IntegerTemplateSelector"
OptionsDataTemplate="{StaticResource OptionsDataTemplate}"
SelectorDataTemplate="{StaticResource IntegerDataTemplate}" />
Somewhere it is going wrong, is there anyone that can point me to the right way to fix it (a work around would be fine as well).
I would like to add I have the same code but with a text box which does work properly, I've added the code below to have a comparison but i haven't been able to find a significant difference.
Text selector (which actually works properly)
<Style x:Key="TextBoxStyle" TargetType="{x:Type telerik:RadWatermarkTextBox}">
<Setter Property="BorderBrush" Value="{StaticResource BasicBrush}" />
<Setter Property="FontFamily" Value="{telerik:Windows8Resource ResourceKey=FontFamilyStrong}" />
<Setter Property="Padding" Value="2,2,0,0" />
<Setter Property="Validation.ErrorTemplate" Value="{StaticResource ErrorTemplate}" />
<Setter Property="telerik:RadWatermarkTextBox.WatermarkTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Margin="2,3,0,0"
FontFamily="Segoe UI"
FontStyle="Italic"
Foreground="{StaticResource WaterMarkBrushNoOpacity}"
Padding="0,-2,0,0"
Text="{Binding}" />
</DataTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="BorderBrush" Value="{StaticResource AccentBrush}" />
</Trigger>
<Trigger Property="IsReadOnly" Value="True">
<Setter Property="BorderBrush" Value="{StaticResource MarkerDisabledBrush}" />
</Trigger>
</Style.Triggers>
</Style>
<!-- String editor -->
<DataTemplate x:Key="StringDataTemplate">
<telerik:RadWatermarkTextBox x:Name="WatermarkTextBox"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Top"
Background="Transparent"
BorderThickness="1"
Style="{StaticResource TextBoxStyle}"
Text="{Binding Path=Value,
UpdateSourceTrigger=PropertyChanged,
NotifyOnSourceUpdated=True}" />
</DataTemplate>
<!-- String as Option -->
<DataTemplate x:Key="OptionsDataTemplate">
<TextBlock Height="20" Text="{Binding Converter={StaticResource StringSelectorObjectToStringConverter}}" />
</DataTemplate>
<local:SelectorTypeTemplateSelector x:Key="StringTemplateSelector"
OptionsDataTemplate="{StaticResource OptionsDataTemplate}"
SelectorDataTemplate="{StaticResource StringDataTemplate}" />
It's really difficult to know what's going on without actually fiddling around with all the bits and pieces (e.g. the RadComboBox style + code), but it would be natural to assume that is has something to do with the drop down automatically closing when it loses focus, especially given that the standard WPF ComboBox has a FocusedDropDown state which opens the popup.
You could try and duplicate the RadComboBox by importing the style from Telerik, and extending the code behind into a new class (and restyle with the imported template). This way you can override methods and attach to events (e.g. Got/LostFocus), and play around with the template to see if you can adjust it to your needs.
However trying to wrestle such behavior into existing controls, just because it is possible to restyle the templates, often just ends up in a lot of grief (and hours wasted).
I have a feeling it would be easier to create a NumericRadComboBox which has the numeric up/down embedded in the combobox itself. So you restyle the RadComboBox to have numeric up/down buttons next to the drop down arrow, and implement the increment/decrement behavior manually.
The solution was rather simple, I was trying to fix it with preview mouse down but what i needed to do was on preview mouse up by adding: PreviewMouseLeftButtonUp="EditorPreviewMouseLeftButtonUp" in the xaml, which made the RadComboBox code as follows:
telerik:RadComboBox x:Name="Editor"
BorderThickness="0"
FontWeight="SemiBold"
ItemTemplateSelector="{StaticResource IntegerTemplateSelector}"
PreviewMouseLeftButtonUp="EditorPreviewMouseLeftButtonUp"
SelectionBoxTemplate="{StaticResource SelectionboxTemplate}"
Validation.ErrorTemplate="{StaticResource ErrorTemplate}" />
The code behind looked lik this:
private void EditorPreviewMouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
var originalSource = e.OriginalSource as FrameworkElement;
if ((originalSource != null) && (originalSource.ParentOfType<TextBox>() != null))
{
e.Handled = true;
}
}
The MouseUp is when the selection changed event is called which causes the combobox to close, by stating the event is finished before that happens it won't close the combobox. All you now have to do is press enter after you've changed the value and it will be selected and updated correctly.

WPF action on LostFocus textbox

I'm working on a WPF application and i have a little problem.
I have 1 ToggleButton and 1 TextBox. When i click on the ToggleButton, the TextBox apears and gets focus. This is good. But now i want that when i click on another textbox or just somewhere else, that the textbox loses his focus and disapears. I tried this with Differnet triggers and setters, but can't get it to work.
My code now:
<ToggleButton x:Name="SearchButton" Width="100" Height="100" BorderThickness="0" Margin="580,0,0,0" Template="{DynamicResource ButtonBaseControlTemplate1}" Panel.ZIndex="1">
<ToggleButton.Style>
<Style TargetType="ToggleButton">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsChecked, ElementName=SearchButton}" Value="True" />
<Condition Binding="{Binding Visibility, ElementName=SearchBox}" Value="Visible"/>
</MultiDataTrigger.Conditions>
<Setter Property="FocusManager.FocusedElement" Value="{Binding ElementName=SearchBox}" />
</MultiDataTrigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton><TextBox x:Name="SearchBox" Margin="100,33,0,34" Visibility="{Binding IsChecked, ElementName=SearchButton, Converter={StaticResource BoolVisibilityConverter}}" Opacity="0" FontSize="24" FontFamily="Arial" Background="{x:Null}" Foreground="#FF7F7F7F" BorderThickness="0">
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="TextBox.IsFocused" Value="False">
<Setter Property="ToggleButton.IsChecked" Value="False" TargetName="SearchButton" />
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
The fact, that the styles in the WPF separated from each other, it's just a bunch of settings setters. We can say, that two different styles for controls, with two different visual trees. So when you're trying to style TextBox to access ToggleButton it does not work, because of its visual tree no ToggleButtons.
In WPF for editing elements in the visual tree, and control in particular, uses a template control or controls placed within view of one Style (but this is usually done with the help of templates, such as DataTemplate, or with ControlTemplate).
I think it will suit you to control the Expander. It already has ToggleButton and content. Example:
XAML
<Expander Header="SearchButton">
<TextBox Text="SearchBox: Opened" Background="Gainsboro" />
</Expander>
Output
To change the view of Expander, you need to change his Style. With it, you can set any form and view of control.
For more information see:
Expander in MSDN
Styling and Templating in MSDN
Customizing the Appearance of an Existing Control by Using a ControlTemplate
Data Templating Overview

XAML trigger template to set visibilty based on another element

I have several StackPanels that change visibility based on ToggleButtons. The code below works if I replace Tag with btn1 on the DataTrigger-lines.
How do I use the value of the Tag property?
<Window x:Class="MyTestApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="TestApp">
<Window.Resources>
<Style x:Key="panelStyle" TargetType="{x:Type StackPanel}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=Tag, Path=IsChecked}" Value="False">
<Setter Property="StackPanel.Visibility" Value="Collapsed" />
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=Tag, Path=IsChecked}" Value="True">
<Setter Property="StackPanel.Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<WrapPanel>
<ToggleButton Content="One" Name="btn1" />
<ToggleButton Content="Two" Name="btn2" />
<StackPanel Style="{StaticResource panelStyle}" Tag="{Binding btn1}">
<Label Content="Data to panel 1" />
</StackPanel>
<StackPanel Style="{StaticResource panelStyle}" Tag="{Binding btn2}">
<Label Content="Data to panel 2" />
</StackPanel>
</WrapPanel>
</Window>
This question is very similar, but I'm missing details on how to pass an element name.
XAML - Generic textbox stylewith triggers / parameters?
Your bindings are incorrect.
In your DataTemplate the bindings should be:
<DataTrigger Binding="{Binding Path=Tag.IsChecked, RelativeSource={RelativeSource Self}}" Value="False">
<Setter Property="StackPanel.Visibility" Value="Collapsed" />
</DataTrigger>
Here the RelativeSource with a mode of Self tells the binding engine that the object to bind against is object to which the style is being applied (e.g. your StackPanel). The PropertyPath of Tag.IsChecked tells the binding engine to look for a property called IsChecked from the object stored in Tag.
Finally the bindings in your StackPanel should be:
<StackPanel Style="{StaticResource panelStyle}" Tag="{Binding ElementName=btn1}">
<Label Content="Data to panel 1" />
</StackPanel>
Here ElementName creates a binding to another element in the logical tree. If you do not explicitly assign to any properties in a Binding as in your original example:
Tag="{Binding btn1}"
The value specified is assigned to the Path property. So this would be the same as:
Tag="{Binding Path=btn1}"
Also note, that using Tag is not considered best practice since it's type is of object and its use is unrestricted, and hence can take on any number of different meanings throughout your project (which often makes it difficult to understand, especially when used in Templates that are located far away from their actual use).
Hope this helps!
Use Converter: set the visibility of StackPanel:
<StackPanel Visivility="{Binding IsChecked, ElementName=btn1, Converter={StaticResource BooleanToVisibilityConverter}}">
...
</StackPanel>

How to set focus in a textbox when user click an expander?

I have an expander...and a textbox. The textbox is hidden by default. when user click on the expander, I am displaying the text box. This is working fine.
What I need is, when user click on the expander...I need to set the focus in the textbox.
Please help me to do this...I tried with following code...but it seems "IsFocused" is readonly property.
Any help would be appreciated !
<StackPanel>
<DockPanel>
<TextBlock DockPanel.Dock="Left" Text="ID"/>
<Expander x:Name="ID" DockPanel.Dock="Right" IsExpanded="False" ExpandDirection="Down">
</Expander>
</DockPanel>
<TextBox Text="{Binding Path=SearchCCCId.Value,UpdateSourceTrigger=PropertyChanged}"
Visibility="{Binding ElementName=ID,Path=IsExpanded,Converter={x:Static local:Converters.BoolToVisibility}}" Width="70" >
<TextBox.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=ID, Path=IsEpanded}" Value="True" >
<Setter Property="IsFocused" Value="True" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</StackPanel>
With all your help, I am able to find out the answer...
<TextBox.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=ID, Path=IsExpanded}" Value="True">
<Setter Property="FocusManager.FocusedElement"
Value="{Binding ElementName=PropertyIDSearch}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
IsFocused is ReadOnly property. You may want to look at these -
How to set focus to textbox using MVVM?
WPF - Set Focus when a button is clicked - No Code Behind
You can handler Expanded event of Expander and set focus inside handler method.
private void OnExpanderExpanded(object sender, RoutedEventArgs args)
{
txtTest.Focus();
}

How can I indicate in an Expander header that collapsed contents have an error

I have expanders that contain text boxes, the text boxes use the wpf validation stuff to draw a red box around them ( text boxes are wrapped in Adorner Decorators to make sure I don't get empty red boxes everywhere when the expanders are collapsed)
I want to indicate in the header of the expander that it has contents that have errors (in case it is in a collapsed state) - an icon or red exclamation mark or something. I think I see a way to do this in code from my validation function (not ideal) but is there a way to do it in xaml? Can I use a style for the expander with a trigger somehow pointing to the Validation.HasError of all children?
thanks for any thoughts..
Trev
If you know the contents of your expander, you can use a MultiDataTrigger to do this:
<Expander>
<Expander.Header>
<TextBlock>
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Text" Value="ERROR"/>
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding ElementName=txtWidth, Path=(Validation.HasError)}" Value="False"/>
<Condition Binding="{Binding ElementName=txtHeight, Path=(Validation.HasError)}" Value="False"/>
</MultiDataTrigger.Conditions>
<Setter Property="Text" Value="NO ERROR"/>
</MultiDataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</Expander.Header>
<StackPanel>
<TextBox x:Name="txtWidth" Text="{Binding Width, ElementName=rect, UpdateSourceTrigger=PropertyChanged, ValidatesOnExceptions=True}"/>
<TextBox x:Name="txtHeight" Text="{Binding Height, ElementName=rect, UpdateSourceTrigger=PropertyChanged, ValidatesOnExceptions=True}"/>
<Rectangle x:Name="rect" Width="100" Height="100" Margin="10" Fill="Green"/>
</StackPanel>
</Expander>
If the contents of the expander aren't known, then you'll probably have to set Binding.NotifyOnValidationError on the TextBoxes and handle the Error attached event.

Resources