Silverlight, itemcontrol LostFocus and GetFocus not firing - c#

Okay, so the situation as like this:
I've got an ItemsControl, which contains several children.
the children are actually a UserControl, this is it's Xaml:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!--DAY HEADER-->
<Border x:Name="dayHeader" Height="20" BorderBrush="#B0B6BE" BorderThickness="1" Grid.Row="0" Background="{StaticResource WeekHeader}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center" TextAlignment="Center"
TextWrapping="NoWrap" Margin="1.5,0,0,0" Text="18"/>
<TextBlock Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center" TextAlignment="Center"
TextWrapping="NoWrap" Margin="2,0,0,0" Text="Thuesday" />
</Grid>
</Border>
<!--DAY HOURS-->
<ItemsControl x:Name="dayHours" Grid.Row="1">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Name="dayHourBorder" Height="30" BorderBrush="#B0B6BE" Width="193" Tag="{Binding Index}" BorderThickness="1,0,1,1" Background="AliceBlue"
MouseLeftButtonDown="dayHourBorder_MouseLeftButtonDown" MouseLeftButtonUp="dayHourBorder_MouseLeftButtonUp"
MouseMove="dayHourBorder_MouseMove" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
IN SHORT
it's a grid that in the first row has a border
and in the second row has an ItemsControl.
Alright now... what i wanna do is, whenever i click between the child ItemControls (day hours) i want them to execute some function on the LostFocus() event and on GotFocus() event.
problem is... they don't fire! and it tried registering to them from every possible angle!
HALP.
UPDATE
I tried executing Focus() on MouseLeftButtonDown, but what happened is, it went straight to OnLostFocus, which is not what i want...
i don't understand it

Here is an overview on focus in Silverlight. The article mentions four conditions that need to be satisfied in order for the control to get focus. You should check those four conditions for your control and it should be fine I suppose.
You should also consider on which element you'd like to receive those events as GotFocus and LostFocus are bubbling events.

I've managed to fix this issue by doing this:
doing: this.Focus();
and then: e.Handled = true;
the problem was that the ItemControl usually can't hold focus, and so the click event bubbles up.
but when i tell him it's Handled, it stops it's bubbling and won't lose the focus.

Related

Hiding/Showing a UserControl WPF

I am building a WPF MVVM application.
What I have:
I have a ShellWindow which looks like this:
It is composed by 2 rows:
1: the hamburger menu (not important) with Height="*"
2: the console with Height="100"
The console is a UserControl:
<UserControl
//namespaces>
<Grid Name="LoggingGrid" Background="Black">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Margin="{StaticResource SmallLeftMargin}">
<Button
x:Name="CollapseBtn"
Width="25"
Height="25"
Click="CollapseBtn_Click"
Content="▲">
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Ellipse Fill="White" />
<ContentPresenter
HorizontalAlignment="Center"
VerticalAlignment="Center"
Content="{TemplateBinding Content}" />
</Grid>
</ControlTemplate>
</Button.Template>
</Button>
<StackPanel Margin="5,0,0,0" Orientation="Horizontal">
<Image
Height="25"
Source="/Images/console-icon.png"
Visibility="Visible" />
<Label
Content="Console"
FontSize="16"
Foreground="White" />
</StackPanel>
</TextBlock>
<Border Grid.Row="1">
<ListView
x:Name="LoggingList"
Margin="5"
Background="Black"
BorderThickness="0"
Foreground="White"
ItemsSource="{Binding Logs, UpdateSourceTrigger=PropertyChanged}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Auto" />
</Border>
</Grid>
</UserControl>
I have omitted the non-important things.
What I want to do:
Whenever the user clicks on the button, the console should collapse and look something like this:
The arrow is also changed.
How can I implement this? What is the best approach using MVVM?
What I have tried:
I have tried using a button click event handler in the code behind - CollapseBtn_Click, just to see what will happen:
private void CollapseBtn_Click(object sender, System.Windows.RoutedEventArgs e)
{
LoggingGrid.Visibility = System.Windows.Visibility.Hidden;
}
Apparently it removes the user control and leaves a white background where it used to be.
Instead of setting the Visibility of the whole LoggingGrid to Hidden, you should set the Visibility of the LoggingList to Collapsed. (For the difference between Hidden and Collapsed, see here: Difference between Visibility.Collapsed and Visibility.Hidden).
Depending on your layout in the ShellWindow you probably have to adjust your row height configuration in the UserControl such that the collapsed LoggingGrid leads to a row with a height of zero.
Regarding MVVM the best approach would be to bind the Button to a bool property ConsoleVisible on your ViewModel such that clicking the button toggles the property between true and false. The styling of the button can be bound to the same property. For the LoggingList Visibility you could use a Binding with a BooleanToVisibilityConverter on the same property.

Strange behaviour in the AutoSuggestBox's suggestions list in UWP

I'm experiencing some strange behaviour with the AutoSuggestBox in UWP platform, especially regarding its suggestion list elements.
I want to customize those elements with an hover effect that makes a Button appear when the pointer enters the item template… and I would like also to stretch the item's content through all the available template width.
This is the code for the AutoSuggestBox (sorry for some non-english property name, but I think it isn't important):
<AutoSuggestBox MinWidth="300" Text="{x:Bind ViewModel.TestoRicerca, Mode=TwoWay}" ItemsSource="{x:Bind ViewModel.ListaRicerca, Mode=OneWay}" QueryIcon="Find">
<AutoSuggestBox.ItemTemplate>
<DataTemplate x:DataType="vm:Colore">
<Grid PointerExited="{x:Bind OnExitPointer}" PointerEntered="{x:Bind OnEnterPointer}" HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<Rectangle Width="30" Height="30" Margin="0,5,15,5" Fill="{x:Bind ColorBrush, Mode=OneWay}" Stroke="LightGray" StrokeThickness="1" RadiusX="2" RadiusY="2" VerticalAlignment="Center"/>
<StackPanel Grid.Column="1" VerticalAlignment="Center">
<TextBlock Text="{x:Bind Nome, Mode=OneWay}" VerticalAlignment="Center" FontWeight="Bold" TextWrapping="Wrap"/>
<TextBlock Text="{x:Bind ColorAsString, Mode=OneWay}" Foreground="LightGray" TextWrapping="Wrap" Margin="0,2,0,0"/>
</StackPanel>
<Button Grid.Column="2" Content="Click here" Visibility="{x:Bind IsHovered, Mode=OneWay}" VerticalAlignment="Center" Click="{x:Bind DisplayDetail}"/>
</Grid>
</DataTemplate>
</AutoSuggestBox.ItemTemplate>
</AutoSuggestBox>
The OnEnterPointer and OnExitPointer functions, placed in the main Grid of the ItemTemplate, should make the Button appear always when the pointer is into the Grid area… but this doesn't happen!
Actually, the OnEnterPointer fires ONLY when the pointer is over the Grid's children!
This is shown here in those photos:
How could I make the hover effect firing in the entire Grid's area?
THe other thing is about stretching the list item's content, as I said before and as you can see in the pictures… in a normal ListView I know how to do it (place a custom Style in ListView.ItemPresenterStyle with the properly Setter), but here it doesn't work somehow, maybe because it isn't a ListViewItem the standard item in that suggestion list…
If you have any idea about this question also, I would like to know it.
I thank you for your attention and your patience.
Best regards

Two AutoCompleteBox controls in two different tabs in wpf

I have used two AutoCompleteBox controls in two different tabs in a wpf window.
Control in first tab is working fine. First Control
But the control in second tab, data is binding and I could see the matched strings in the dropdown list.
I couldn't select the items from the list using mouse or arrow keys. Second Control
When I moved the second control to new window, it is working fine.
I couldn't understand what is the actual issue?
Please find below code:
Autocompletebox in first tab
<ctrls:AutoCompleteBox Grid.Column="1" x:Name="txtFirst" VerticalAlignment="Center" Margin="0,0,0,10" />
Autocompletebox in Second tab
<ctrls:AutoCompleteBox Grid.Column="1" x:Name="txtSecond" VerticalAlignment="Center" Margin="0,0,0,10" />
Xaml code for Tab control
<TabControl Grid.Row="1"
x:Name="tabCtrl"
SelectionChanged="tabCtrl_SelectionChanged">
<TabItem x:Name="tab1"
Header="First">
<ScrollViewer>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="500" />
</Grid.ColumnDefinitions>
<TextBlock Text="First"
VerticalAlignment="Center"
Margin="0,0,0,10" />
<ctrls:AutoCompleteBox Grid.Column="1"
x:Name="txtFirst"
VerticalAlignment="Center"
Margin="0,0,0,10" />
</Grid>
</ScrollViewer>
</TabItem>
<TabItem x:Name="tab2"
Header="Second">
<ScrollViewer>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="500" />
</Grid.ColumnDefinitions>
<TextBlock Text="Second"
VerticalAlignment="Center"
Margin="0,0,0,10" />
<ctrls:AutoCompleteBox Grid.Column="1"
x:Name="txtSecond"
VerticalAlignment="Center"
Margin="0,0,0,10" />
</Grid>
</ScrollViewer>
</TabItem>
</TabControl>
And the code behind
var data = db.tblname.Select(c => c.propertyname).ToList();
txtFirst.ItemsSource = data;
var data1 = db.tblname.Select(c => c.propertyname).ToList();
txtSecond.ItemsSource = data1;
Your C# code is fine.
You should take a look at the XAML.
(Provide XAML to us as well.)
After thorough debugging of my code, I figured out that the issue was due to SelectionChanged event of TabControl.
Whenever I select an item from the Autocompletebox control, SelectionChanged event of TabControl was getting fired, which led to chaos, as my binding logic for Autocompletebox was in SelectionChanged event.
Still I am not getting why do my Autocompletebox control triggers SelectionChanged event of TabControl without the registeration of SelectionChanged event for Autocompletebox Control.
But Below code overcame the issue
private void tabCtrl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.Source is TabControl)
{
// Business logic for binding autocompletebox
}
}
Thanks everyone for their support!

Tab Order on Dynamically Loaded Controls

I have a situation where I am trying to set the tab order (tabindex) for controls that are loaded dynamically. The main XAML looks like this:
<ItemsControl DockPanel.Dock="Top" ItemsSource="{Binding ItemsDataSource}" Name="overlayItems" ItemTemplate="{StaticResource DetailsTemplate}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
For example purposes, assume the DetailsTemplate is something simple like this:
<DataTemplate x:Key="DetailsTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="150" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="22" />
<RowDefinition Height="22" />
<RowDefinition Height="22" />
</Grid.RowDefinitions>
<Label Grid.Column="0" Grid.Row="0" Padding="0">Field 1</Label>
<TextBox Grid.Column="1" Grid.Row="0" Name="field1TextBox" TabIndex="0" Text="{Binding Field1Value}"/>
<Label Grid.Column="0" Grid.Row="1" Padding="0">Field 2</Label>
<TextBox Grid.Column="1" Grid.Row="1" Name="field2TextBox" TabIndex="1" Text="{Binding Field2Value}"/>
<Label Grid.Column="0" Grid.Row="2" Padding="0">Field 3</Label>
<TextBox Grid.Column="1" Grid.Row="2" Name="field3TextBox" TabIndex="2" Text="{Binding Field3Value}"/>
</Grid>
</DataTemplate>
This XAML works just fine except for the resulting tab order.
Assuming that the ItemsDataSource is a collection of a class and contains 3 instances of that class, three sets of the DetailsTemplate data template are created. However the tab order does not change, every field1TextBox remains at TabIndex 0. This means, instead of tabbing from the first instances of field1TextBox, to field2TextBox, to field3TextBox, the tab goes from the first instance of field1TextBox to the second instance of field1TextBox then to the third instance of field1TextBox then to the first instance of field2TextBox, and so on. My question is, how do I get the tab order corrected where, say, the second instance of the data template would have its text boxes tab indexes updated to 3, 4 and 5 respectively?
You'll find the answer in the KeyboardNavigation.TabNavigation Attached Property page from MSDN. This property Gets or sets the logical tab navigation behavior for the children of the element that this property is set on.
There are several possible values in the KeyboardNavigationMode Enumeration used that affect the tabbing order in different ways, but you're after the Local value, which has the effect that Tab Indexes are considered on local subtree only inside this container and ... [Navigation leaves the containing element when an edge is reached].
<Grid KeyboardNavigation.TabNavigation="Local">
...
</Grid>

Textbox in popup doesn't get focus in WPF application

I'm building a window for a kiosk application that has an admin screen to connect to a wifi network. Actually, I'm porting an existing WinForms app that already does this, but doesn't give us the flexibility we want to create a more interesting UI. So, we're moving to WPF.
The window is pretty straightforward, it has a listview to show networks that it finds, and if you click on one, it will connect to it. In order to connect, we need to prompt for the security code for that network if it needs one. To do this, we open a popup that has three sections - a "dialog-y" prompt section at the top, a spacer row, and a blank border that will sit behind an onscreen keyboard, but have nice rounded corners.
That top section has a header, a text box, and two buttons, connect and cancel. Again, nothing complex.
All this works. You click a network, we show the popup and the keyboard, except: the textbox for the passcode never gets the focus. Even if you click on it. No focus. The only trick I've found to get it to focus is to click off the popup (like back on the listview, which is already ignoring clicks if the popup is open, so it's safe), then click back on the textbox, and voila! focus. I really don't think I want to put that in a user manual though.
Here's the popup portion of the xaml:
<Popup x:Name="popPasscode" Placement="Top" HorizontalOffset="50" VerticalOffset="1000" AllowsTransparency="True" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="50" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Border Grid.Row="0" Background="White" CornerRadius="20" Width="600" Height="400">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Border Grid.Row="0" Background="#464646" Height="50" Margin="8,10,8,0" CornerRadius="25" >
<Label x:Name="lblTitleSecurityCode" Content="Enter the security code" Foreground="White" FontFamily="Arial" FontSize="30" FontWeight="Bold" HorizontalAlignment="Center"/>
</Border>
<TextBox Grid.Row="1" x:Name="tbPasscode" Height="50" FontFamily="Arial" FontSize="30" Margin="40,0,40,0"/>
<StackPanel Grid.Row="2" Orientation="Horizontal" Margin="10,0,10,10" HorizontalAlignment="Center">
<Controls:ImageButton x:Name="btnCodeConnect" Content="Connect" Height="70" Width="275" Foreground="Black" Style="{DynamicResource PlainButton}" FontFamily="Arial" FontSize="30" FontWeight="Bold" Click="btnCodeConnect_Click" HorizontalAlignment="Center" VerticalAlignment="Center" />
<Controls:ImageButton x:Name="btnCodeCancel" Content="Cancel" Height="70" Width="275" Foreground="Black" Style="{DynamicResource PlainButton}" FontFamily="Arial" FontSize="30" FontWeight="Bold" Click="btnCodeCancel_Click" HorizontalAlignment="Center" VerticalAlignment="Center" />
</StackPanel>
</Grid>
</Border>
<Border Grid.Row="2" x:Name="brdrKbd" Background="White" CornerRadius="20" Width="1200" Height="420"/>
</Grid>
</Popup>
Here's what I'm currently trying to do during the listview click event to get focus to the control. Note that I tried to fake the "set focus to the listview, then set it to the textbox, but that didn't work.
// set the popup location and width and keyboard border width based on the current screen width
popPasscode.IsOpen = true;
// open the on-screen keyboard - synchronous call, doesn't return until it's open and idle
FocusManager.SetFocusedElement(this, lvAvailNetworks);
tbPasscode.Focusable = true;
FocusManager.SetFocusedElement(popPasscode, tbPasscode);
I've tried a couple different things for the DependencyElement for tbPasscode, but I really have no idea what I'm doing, or that what I'm doing is making any difference. Oh, did I mention I just finished my first week of WPF coding? Yup, WPF newbie alert.
I saw this post, but it didn't help much, since I thought I was already doing all that.
Instead of MouseDown, register to MouseUp event on ListView/ListViewItem.
In the handler you can do
popPasscode.IsOpen = true;
Keyboard.Focus(tbPasscode);
The MouseUp on your ListView takes focus away from the Popup, so open your Popup in MouseUp instead of MouseDown

Categories

Resources