I have a combobox that is editable and a textbox.
<TextBox x:Name="textBox" HorizontalAlignment="Left" Height="23" Margin="86,149,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120"/>
<ComboBox x:Name="comboBox" HorizontalAlignment="Left" VerticalAlignment="Top" Width="120" Margin="282,150,0,0" IsEditable="True" PreviewMouseDown="ComboBox_PreviewMouseDown"/>
I don't understand why ComboBox_PreviewMouseDown does not trigger, when the focus is on the textbox and I click on the combobox. It just highlights the text in the combobox and sets the focus. Clicking in the combobox when it already has the focus, PreviewMouseDown fires.
Is that what's happening here? Why is a PreviewMouseDown in an unfocused combobox not working?
When ComboBox.IsEditable is set to True, the ComboBox internally sets the focus (and keyboard focus) to the edit TextBox to make it instantly available for text input. This makes total sense as the intention when clicking the edit TextBox is always to enter or edit some text. Otherwise, the user would have to click the TextBox twice to make it receive focus for text input (keyboard focus).
So, to prevent focus stealing, the author marked the MouseDown event as handled i.e. RoutedEventArgs.Handled is set to true. (This is the reason why most non-preview events are marked handled by most controls).
Also, the author wanted to prevent the moving of the caret when clicked into the edit TextBox for the first time (to give it focus): the PreviewMouseDown event's RoutedEventArgs.Handled will only be set to true, if the edit TextBox has no keyboard focus and the drop-down panel is closed. (That's why the second click into the TextBox will pass through to be handled by an added event handler).
To achieve the behavior you expect, you have to handle the UIElement.PreviewGotKeyboardFocus event or the attached Keyboard.PreviewGotKeyboardFocusevent on the ComboBox.
Alternatively register the event handler using the UIElement.AddHandler method and set the handledEventsToo parameter to true:
this.MyComboBox.AddHandler(
UIElement.PreviewMouseDownEvent,
new RoutedEventHandler(MyComboBox_PreviewMouseDown),
true);
I ran into this same issue myself. A simple and effective workaround is to wrap your ComboBox in a lightweight ContentPresenter, then attach your PreviewMouseDown handler to that, like so:
<ContentPresenter x:Name="MyComboBoxWrapper"
PreviewMouseDown="MyComboBoxWrapper_PreviewMouseDown">
<ContentPresenter.Content>
<ComboBox x:Name="MyComboBox" />
</ContentPresenter.Content>
</ContentPresenter>
Additionally, since this control gets the PreviewMouseDown event before the ComboBox does, you not only can use it to pre-process events before the ComboBox even sees them, but you can cut off the ComboBox entirely by setting the event arg's handled property to 'true.'
Works like a charm! No subclassing or other tricks needed and it only requires a lightweight control in the tree!
Notes
As some may have considered, technically you could attach the PreviewMouseDown event to any ancestor of your ComboBox, but you then may have to include logic in that handler to determine if you're actually clicking on the ComboBox vs something else.
By using an explicit ContentPresenter (an incredibly lightweight element that itself doesn't have any rendering logic. It simply hosts other elements), you now have a dedicated PreviewMouseDown handler just for this control. Plus, it makes it more portable should you need to move it around since the two items can travel together.
Related
I are facing issue with GridView Control. We had a working Windows Store App on 8.1 where GridView left and right mouse clicks had different functionality. In the case of left mouse click, we used to use “ItemClick” event which performs navigation to another XAML page. On right click of GridItem, it gets selected and shows the appbar, we have used “SelectionChanged” event for this.
We are now migrating our existing windows store app to UWP Application, we have used same gridView Code, we find significant difference in functionality and look & feel, we don’t see GridView Item Selected like above picture. We see “ItemClick” and “SelectionChanged” are working together. The flow is something like that on left click on the item, the control goes to SelectionChanged event and then ItemClick. We were not able to differentiate actions like Left Mouse Click and Right Mouse click, since both events are getting fired up upon clicking on left click/tapping. We have different functionality on left and right clicks of mouse.
Need help on how to mimic windows 8.1 functionality in UWP.
My requirement was the I wanted to use Right Click/Long Tapped to select an item and take an action accordingly from App Bar Buttons and on Left Click/Tap should redirect me to the next XAML Page. The problem I was facing was the on Right Click, I wasnt able to detect that which items of GridView has been clicked and how can I add that into SelectedItem.
What I did was, I introduced extra Grid in DataTemplate of GridView. Within this Grid, I added RightTapped event.
The sample code snippet is
<GridView x:Name="ItemGridView"
ItemsSource="{Binding Source={StaticResource ItemsViewSource}}"
IsItemClickEnabled="True"
SelectionMode="Single" ItemClick="ItemGridView_ItemClick"
SelectionChanged="ItemGridView_SelectionChanged">
<GridView.ItemTemplate>
<DataTemplate>
<Grid RightTapped="Grid_RightTapped">
<Border Background="White" BorderThickness="0" Width="210" Height="85">
<TextBlock Text="{Binding FileName}" />
</Border>
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
The event name is Grid_RightTapped. This helped me detect that from which GridViewItem, I got the long tap/right click.
The code-behind for this is:
private void Grid_RightTapped(object sender, RightTappedRoutedEventArgs e)
{
Song selectedItem = (sender as Grid).DataContext as Song;
//the above line will get the exact GridViewItem where the User Clicked
this.ItemGridView.SelectedItem = selectedItem;
//the above line will add the item into SelectedItem and hence, I can take any action after this which I require
}
}
The reason we are doing this way is, because now we can add clicked item into the GridView SelectedItem using Right Click. Now in UWP, clicked items are added into SelectedItem using left click only. And with left click, I can navigate to another page using ItemClick event.
You are correct, there has been a change in the interaction model behavior. According to MSDN article How to change the interaction mode (XAML)
For selection, set IsItemClickEnabled to false and SelectionMode to
any value except ListViewSelectionMode.None and handle the
SelectionChanged event (ItemClick is not raised in this case).
For invoke, set IsItemClickEnabled to true and SelectionMode to
ListViewSelectionMode.None and handle the ItemClick event
(SelectionChanged is not raised in this case).
Another combination is to set IsItemClickEnabled to false and
SelectionMode to ListViewSelectionMode.None. This is the read-only
configuration.
A final configuration, which is used least often, is to set
IsItemClickEnabled to true and SelectionMode to any value except
ListViewSelectionMode.None. In this configuration first ItemClick is
raised and then SelectionChanged is raised.
You seem to be using the last option - IsItemClickEnabled is set to true and SelectionMode is set to something that's not None. According the Microsoft, this is used least often so maybe it would be a good idea to rethink this design?
Since you haven't shared any code that you already tried, I will just throw in one idea: maybe playing around with Tappedand RightTapped event handlers could help you differentiate between the two more easily?
To identify left and right click, for right click you can use RightTapped event
<GridView x:Name="categoryItemsGV"
Margin="5,5,0,0"
IsItemClickEnabled="True"
ItemClick="categoryItemsGV_ItemClick"
IsRightTapEnabled="True"
RightTapped="categoryItemsGV_RightTapped"
SelectionMode="Single"
SizeChanged="categoryItemsGV_SizeChanged"
ItemsSource="{Binding}">
and .cs code is below:
private void categoryItemsGV_RightTapped(object sender, RightTappedRoutedEventArgs e)
{
var tablemod = (sender as GridView).SelectedItem;
}
From RightTapped the item over which the mouse was right clicked can be obtained from e.OriginalSource
<GridView x:Name="myGridView" VerticalAlignment="Center">
<GridView.ContextFlyout>
<MenuFlyout>
<MenuFlyoutItem Text="Reset"/>
<MenuFlyoutSeparator/>
<MenuFlyoutItem Text="Repeat"/>
<MenuFlyoutItem Text="Shuffle"/>
</MenuFlyout>
</GridView.ContextFlyout>
</GridView>
Private Sub myGridView_RightTapped(sender As Object, e As RightTappedRoutedEventArgs) Handles myGridView.RightTapped
myGridView.SelectedItem = e.OriginalSource
End Sub
Now that RightClick has selected the desired item, further action like delete, copy can be executed on it.
I have a TextBox.
I want it to be in the Disabled state, so that I can drag it. Once I double click it I want it back to be Enabled.
I can use ReadOnly property for this purpose. But If I use ReadOnly, then I am unable to Drag the TextBox, instead I get selection.
My actual reason for doing this is I want to use TextBox as TreeViewItem and I would like to allow features like Rename and Rearrange using drag-drop.
If anybody can suggest something like custom control that I can create and override some method?
I suggest to wrap the TextBox inside Grid. And set IsHitTestVisible to false for textBox. This will avoid all mouse events for TextBox. Now hook all your drag events to grid and it will work.
<Grid Background="Transparent" VerticalAlignment="Center">
<TextBox IsHitTestVisible="False" Margin="5" Text="Some text"/>
</Grid>
I have 3 conrtols placed on my Window in WPF, each control contains one or more TextBox and Button, when a new control is selected I would like to change the IsDefault to that button. What I am currently doing is when the TextBox's GotFocus event is fired, I change my Button to IsDefault. This works the first time but when I change from one control to another, and back to the first selected control the second controls IsDefault is still true and when enter is pressed it fires the Click event on the incorrect control.
Is there a way that i can clear all IsDefault properties on my window or what is a better solution to my current way of doing this? See image below for example, when enter is pressed the Button with "..." is fired instead of quick search.
XAML (Update)
<odc:OdcTextBox Text="{Binding AccountNumber, UpdateSourceTrigger=PropertyChanged}" MinWidth="100" Name="txtAccountNumber" Grid.Row="1" Grid.Column="1" VerticalAlignment="Center" Margin="{Binding TextMargin}">
<odc:OdcTextBox.Buttons>
<Button IsDefault="{Binding ElementName=txtAccountNumber, Path=IsKeyboardFocusWithin}" Width="30" Style="{StaticResource DionysusButton}" x:Name="btnCdv" Content="...">
</Button>
</odc:OdcTextBox.Buttons>
</odc:OdcTextBox>
<Button IsDefault={Binding IsKeyboardFocusWithin, ElementName=ThisGroupBox} />
EDIT:
Your code is slightly different in that you are providing buttons to some custom control. These buttons are declared in a different scope to where they end up (ie I assume they end up inside the OdcTextBox template somewhere). I suspect this is why WPF can't find the named element since that element is named in an outer scope.
You could try using RelativeSource to find the parent OdcTextBox instead:
<Button IsDefault="{Binding IsKeyboardFocusWithin, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type odc:OdcTextBox}}}"
Width="30" Style="{StaticResource DionysusButton}" x:Name="btnCdv" Content="...">
Similarly to how you're using the TextBox GotFocus event, you could do the inverse of this and use the LostFocus event to reset the IsDefault Property
In my Windows 8 Metro project, I'm using a class derived from ContentControl (let's call it MyControl) to present my content. Inside MyControl I have a ScrollViewer. Because I want my control to handle keyboard events, I need to be able to set the focus to my control. However, I also want the option to let the scrollviewer handle keyevents, such as arrow keys and PageUp/Down. More precisely, I want this to be an option that another programmer can turn on or off. This means that sometimes, I want MyControl to be a tab-stop, and sometimes I want ScrollViewer to be a tab-stop, but never both.
The issue is that I don't want to expose the inner workings of MyControl to other programmers. That is, they ideally should be able to use MyControl.IsTabStop and leave the logic of placing the actual tab-stop with my Control (to put in MyControl or ScrollViewer).
Is there any good way to achieve this, or do I somehow have to work around it by providing a separate function to make my control a tab stop?
If you look at my test XAML you'll see I'm doing nothing, yet the up/down keys in the TextBox work to go between lines of text and they scroll the ScrollViewer when there is no line of text to go to. This is likely achieved by the KeyDown handlers setting the e.Handled value to true when they don't want the key event to bubble up (as when the TextBox already handled it) and leaving it false when the event is not handled, which lets the ScrollViewer handle it. The event will always trigger on the TextBox if it has focus, but it bubbles up the visual tree if it is not handled. It does not seem that you have to do anything more than just deciding whether you want to mark the key events as handled or not.
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<ScrollViewer
IsTabStop="True">
<Grid
Width="2000"
Height="2000">
<Button
Margin="149,342,0,311">
<Button>
<TextBox
AcceptsReturn="True"
Height="400"
Width="200"/></Button>
</Button>
</Grid>
</ScrollViewer>
</Grid>
I have made a textbox in XAML, which goes like this:
<TextBox x:Name="search"
TextWrapping="Wrap"
VerticalAlignment="Top"
Margin="-12,-13,45,0"
Background="#FFB2B2B8"
BorderBrush="Transparent"
Foreground="White"
inputScope="Search"
SelectionForeground="#FF72BCE6" />
and whenever I tap on the textbox to write something, its background changes. How can I set the background so that it is always on the same color?
Make use of the focus event handler.
Edit: Explaining further,
attach an onfocus event handler to the textbox
in the method, set the background colour of the textbox to the colour you desire.
Expanded even further, in case you want to find out more on what i mean, check this out
http://www.limguohong.com/2012/09/windows-phone-7-textbox-on-focus-color/
You may try creating a new template and making the background color stay constant when focused.