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

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();
}

Related

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

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.

WPF: How to set bool to true from DataTemplate for Button?

I know it is possible to do this by working with ICommand, but since this is the only place in my whole project where this is needed, I am asking myself, if there is maybe a better solution than implementing RelayCommand and ICommand and an additional method in my otherwise property-only class?
Maybe my scenario may help here:
I have a ListView which is bound to a list of properties (this is a custom-class I made to display those).
I have a button in eacht row of entries, that I want to set the "IsToDelete"-Property to true.
If "IsToDelete" is true, all the controls I show in my ListView will collapse.
The whole logic is up to this point in DataTemplates, the one for my button looks like this:
<DataTemplate x:Key="DeleteButtonTemplate">
<Button Name="bt_Delete"
Command="{Binding RelativeSource={RelativeSource AncestorType=ListView}, Path=ItemSource.DeleteClicked}">
<Image Height="16" Width="16" Source="Images\RecycleBin\VSO_RecycleBin_16x.png"/>
<Button.Style>
<Style TargetType="{x:Type Button}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsToDelete}" Value="True">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</DataTemplate>
Note the command in this DataTemplate is currently not working as intended, that is why I even got to the question ;)
In the optimal case I'd just have to do something like:
<Setter Property="{Binding IsToDelete}" Value="True"/>
So, is there a way to solve it like this or at least in a less complicated way than ICommand with RelayCommand?
why not use ToggleButton and bind IsChecked property to IsToDelete property of a viewModel?
simplified example with ItemsControl
<ItemsControl>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<ToggleButton Content="X" IsChecked="{Binding Path=IsToDelete}"/>
<Border Width="100"
Background="MediumPurple"
Margin="5">
<Border.Style>
<Style TargetType="Border">
<Setter Property="Visibility" Value="Visible"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsToDelete}" Value="True">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
</Border>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
You could use the Click eventhandler of the Button. Then you don't need any Commands.
private void bt_Delete_Click(object sender, RoutedEventArgs e)
{
var btn = sender as Button;
YourClass dc = btn.DataContext as YourClass;
dc.IsToDelete = true;
}
I don't really like this solution, but I think, it would work.

How to animate a DataGrid height

All,
I have a WPF datagrid in which there is a template column defined as follows:
<DataGridTemplateColumn Width="105">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Height="35">
<Button Style="{StaticResource tableButtonStyle}">
<ContentControl/>
</Button>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
The button style (which only displays the button when the user moves the mouse over a specific data grid row) is as follows:
<!-- Disappearing button for tables -->
<Style x:Key="tableButtonStyle" TargetType="Button" BasedOn="{StaticResource {x:Static ToolBar.ButtonStyleKey}}">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type DataGridRow}},Path=IsMouseOver}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
I would like to animate the height of the datagrid so that it is 'X' units high when the buttons are hidden, or 'Y' units high when the buttons are displayed. Can this be achieved in the xaml markup?
Thanks in advance!
I don't know if there's a way to do that in XAML(I don't know it because i'm new to xaml).
But what I would do that with code-behind. I would use a fancy animation, something like:
private Storyboard sb=new StoryBoard();
private DoubleAnimation da=new DoubleAnimation();
da.From=datagrid.actualHeight;
da.to=x;
da.Duration = new Duration(TimeSpan.FromSeconds(0.5));
Storyboard.SetTargetProperty(da, new PropertyPath(yourDatagrid.HeigthProperty));
sb.Children.Add(da);
yourDatagrid.BeginStoryboard(sb);
and maybe you can get this inside a ClickEvent.
Hope this help!

clicking the hyperlink inside WPF listview is not selecting the corresponding row

I have following listview with a gridview column and cell template for that gridview column. But when I click on the "hyperlink", the corresponding gridview row is not getting selected.
Could anyone give me a solution please
DATA TEMPLATE
<DataTemplate x:Key="smTemplate">
<StackPanel>
<TextBlock TextWrapping="Wrap" Text="{Binding SM}" />
<TextBlock>
<Hyperlink x:Name="tHLink" Click="thL_Click" KeyboardNavigation.IsTabStop="True">
<TextBlock Text="TH" />
</Hyperlink>
</TextBlock>
</StackPanel>
</DataTemplate>
LIST VIEW
<ListView Focusable="True">
<ListView.View>
<GridView>
<GridViewColumn Header="DM" CellTemplate="{StaticResource smTemplate}" />
</GridView>
</ListView.View>
</ListView>
try changing ListViewItem style so when it gains keyboard focus it will be automatically selected:
<ListView>
<!-- ..... -->
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Style.Triggers>
<EventTrigger RoutedEvent="PreviewGotKeyboardFocus">
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="IsSelected">
<DiscreteBooleanKeyFrame Value="True" KeyTime="0:0:0" />
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
</ListView>
Hyperlink overrides OnMouseLeftButtonDown and OnMouseLeftButtonUp. In those methods, e.Handled = true is set after processing your event handlers, so you can't override it by attaching events to the control in XAML. In order to fix the behavior to suit your needs, you'll need to create a class derived from Hyperlink and override mouse handling events.
However, all this is unnecessary. Judging by you code, Hyperlink causes more problems than it solves, so I suggest replacing it with a single TextBlock control with a custom style.
<TextBlock Text="TH" TextDecorations="Underline" Cursor="Hand"
Foreground="{x:Static SystemColors.HotTrackBrush}"/>
[Not a good answer]
I find a good solution here. and I just copied and pasted following code and I used it. its worked. even if you click on white blank , the corresponding row will be selected.
<ControlTemplate TargetType="ListViewItem" x:Key="rowStyle1">
<Grid x:Name="backGroundPanel">
<GridViewRowPresenter Content="{TemplateBinding Content}" />
<Rectangle Fill="White" Opacity="0"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="backGroundPanel" Property="Background" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<Style x:Key="columnHeaderContianerStyle" TargetType="ListViewItem">
<Setter Property="Template" Value="{StaticResource ResourceKey=rowStyle1}"/>
</Style>
and I set property "ItemContainerStyle" of listview like code below:
<ListView ItemContainerStyle="{DynamicResource columnHeaderContianerStyle}" ... >
[a revised answer]
The above solution is not working if we are interested in capturing mouse in column control. because the rectangle in backGroundPanel capture mouse events ,then it prevents mouse events being captured by GridViewRowPresenter. so we must use a strategy that have 2 features:
Mouse events should be captured by inner column controls.
When user clicked every Where in the row, The row must be selected.
so, the solution get simpler this time. I used below code for my ListView's ItemContainerStyle.
<Style x:Key="columnHeaderContianerStyle" TargetType="ListViewItem">
<EventSetter Event="PreviewMouseDown" Handler="ListViewItem_PreviewMouseDown"></EventSetter>
</Style>
and event Handler is :
private void ListViewItem_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
if (sender is ListViewItem)
{
ListViewItem s = (ListViewItem)sender;
s.IsSelected = true;
}
}
It works fine with 2 mentioned features.

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