I attempted to follow a pattern described in an answer to this question.
How to set focus to textbox using MVVM?
However, I am having trouble with the concept of keyboard focus. If I have notepad or some other application running at the same time as my WPF application and click on notepad to put the keyboard focus there, then do something to cause my other application to put the focus into one of its text boxes, then the trigger gives the visual cue that my application's text box now has the keyboard focus. However when I start typing I can see that is not the case because the text is actually going into notepad.
Here is the xaml for my trigger.
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<DataTrigger Binding="{Binding ReadyForDataEntry}" Value="True">
<Setter Property="FocusManager.FocusedElement" Value="{Binding RelativeSource={RelativeSource Self}}" />
</DataTrigger>
<Trigger Property="IsKeyboardFocused" Value="true">
<Setter Property="Background" Value="Lavender"/>
<Setter Property="BorderBrush" Value="Blue"/>
</Trigger>
</Style.Triggers>
</Style>
Essentially the textbox will sometimes light up with the border and background color indicating that IsKeyboardFocused = true for that textbox, even though keyboard entry will be received by whatever application (e.g., one note, notepad) was last clicked in. What am I missing? Why would that WPF control have IsKeyboardFocused set true when the keyboard focus is clearly not true at all?
You're not doing anything wrong; this is a known quirk of WPF.
When a control receives logical focus, WPF attempts to give it keyboard focus as well. However, when you assign keyboard focus in an inactive WPF application, the application behaves as if it's active. That means, among other things, a focused TextBox will show a blinking caret, and IsKeyboardFocused and related properties will be set.
I have seen this issue in the past, and it was trivial to reproduce.
Xaml:
<Window x:Class="WpfTest.FocusTest"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<StackPanel HorizontalAlignment="Center"
VerticalAlignment="Center">
<TextBox x:Name="_textBox"
Width="150">
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="IsKeyboardFocused"
Value="true">
<Setter Property="Background"
Value="Lavender" />
<Setter Property="BorderBrush"
Value="Blue" />
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
<Button Margin="0,7,0,0"
Content="_Click Me"
Click="OnButtonClick" />
</StackPanel>
</Grid>
</Window>
Code behind:
public partial class FocusTest
{
public FocusTest()
{
InitializeComponent();
}
private void OnButtonClick(object sender, RoutedEventArgs e)
{
_textBox.Text = "";
// NOTE: Requires System.Reactive.Core, available in NuGet.
System.Reactive.Concurrency.Scheduler.Default.Schedule(
TimeSpan.FromSeconds(5),
() => this.Dispatcher.BeginInvoke(new Action(this.SetFocus)));
}
private void SetFocus()
{
_textBox.Text = "Focused";
FocusManager.SetFocusedElement(_textBox, _textBox);
}
}
Hit the button, Alt+Tab over to Notepad, and wait 5 seconds for the TextBox to receive focus. The IsKeyboardFocused trigger is fired, and the blinking caret appears, but keyboard input is still sent to Notepad.
The key point here is that the problem only arises when an element is given focus while another application is active (hence the artificial delay). Note that the problem still arises if you replace the SetFocusedElement call with Keyboard.Focus(_textBox), _textBox.Focus(), and other variations.
Unfortunately, I am not aware of a reliable, non-hacky way of fixing this issue. I don't recall how much time I spent on it, but I ultimately decided it wasn't worth the trouble. It's just not something that comes up that often.
Related
I am using DevExpress for a WPF application, I want to hit a toggle button and make the contents in a richTextBox bold, the manual which is provided here suggests to use ToggleFontBoldCommand as the command. In my WPF application in the xaml file I have added the following code:
<telerik:RadToggleButton CommandTarget="{Binding ElementName=doc}" Command="com:ToggleFontBoldCommand" Content="B"/>
doc is a richTextBox. com is the namespace of DevExpress commands' namespaces (xmlns:com="clr-namespace:DevExpress.XtraRichEdit.Commands; assembly=DevExpress.RichEdit.v16.1.Core"). The point is that Visual Studio can not find the command. I believe that I am wrong with the CommandTarget but I do not know what is wrong.
I'm just using the standard WPF ToggleButton and TextBox in this answer, but I believe the solution should also work with your telerik and DevExpress controls.
If all you want is to make the text in the RichTextBox bold when the RadToggleButton has been clicked you should be able to side step the whole command thing and use something similar to the following:
<ToggleButton x:Name="BoldToggle" />
<TextBox>
<TextBox.Style>
<Style TargetType="TextBox">
<Setter Property="FontWeight" Value="Normal"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked, ElementName=BoldToggle}" Value="true">
<Setter Property="FontWeight" Value="Bold"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
The style on the TextBox changes the FontWeight property from "Normal" to "Bold" when the ToggleButton's IsChecked property is "true".
Does this get you what you need?
I have a UserControl that I'm writing that will have a TextBox and Button. When the user clicks the button, I'd like the current date/time to be placed into the TextBox. The code below has two issues:
For some reason the binding is throwing an exception "Two-way binding requires Path or XPath".
If I just set the value to something like "Test", then it works but only while the button itself is pressed, once I lift the mouse button the text goes away.
In essence, I'd like the value to be set at mouse click not during. I'd like to keep this pure xaml if possible, but I understand if it needs to be in the code-behind. Any help would be appreciated!
<Button x:Name="ClockGo">
<Image Source="/Best.Controls;component/Resources/clock_go.png" />
</Button>
<TextBox HorizontalAlignment="Stretch">
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=ClockGo, Path=IsPressed}" Value="True">
<Setter Property="Text" Value="{Binding Source={x:Static sys:DateTime.Today}, StringFormat='{}{0:MM/dd/yyyy}'}" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
You should be able to get rid of "Two-way binding requires Path or XPath" exception by setting the binding mode to OneWay. Textbox has a two way binding by default and I believe the exception is due to the value conversion.
<Setter Property="Text" Value="{Binding Source={x:Static sys:DateTime.Now}, StringFormat='{}{0:MM/dd/yyyy hh:mm:ss}', Mode=OneWay}" />
On your second point where the value only shown when the button is pressed and goes away after button click is released, this is the expected behaviour. The Trigger Setter only apply when the binding condition is true, it will be revert to default value when the condition no longer true.
Please refer to MSDN site on the remark section which spells out above behaviour: http://msdn.microsoft.com/en-us/library/system.windows.trigger.aspx
Unless you have a very strong reason to stick with XAML based solution, code behind seems to be the better option here instead of tweaking with triggers.
I have a DataTemplate that is used by a ListBox to provide the 'look' for each ListBoxItem. In addition and because these ListBoxItems can be wider than the column in which they're held, I also have a Popup that is drawn over the top of the ListBoxItem if the mouse is over this item.
The Popup uses the same ContentTemplate as the item it covers and therefore the appearance is that the item under the mouse simply stops clipping to the bounds of the ListBox it resides in. It works well except I cannot successfully pass mouse events back to the control it is obscuring, so that the underlying control can detect a drag operation starting.
<!--This datatemplate is used to create a popup over the listboxitem in ItemsView.xaml-->
<DataTemplate x:Key="PopupDaybookItemDataTemplate">
<StackPanel x:Name="pdidt">
<Popup x:Name="myPopup" PlacementTarget="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem}}" Placement="Relative" StaysOpen="True">
<Popup.Style>
<Style TargetType="{x:Type Popup}">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding ElementName=myPopup, Path=IsMouseOver}" Value="True" />
</MultiDataTrigger.Conditions>
<Setter Property="IsOpen" Value="True" />
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Mode=OneWay, ElementName=pdidt, Path=IsMouseOver}" Value="True" />
</MultiDataTrigger.Conditions>
<Setter Property="IsOpen" Value="True" />
</MultiDataTrigger>
</Style.Triggers>
</Style>
</Popup.Style>
<ListBoxItem Style="{StaticResource DayBookItemStyle}"
PreviewMouseDown="ItemListPopup_OnMouseButtonEvent"
MouseDown="ItemListPopup_OnMouseButtonEvent"
PreviewMouseMove="ItemListPopup_OnMouseEvent"
MouseMove="ItemListPopup_OnMouseEvent"
>
<ContentPresenter ContentTemplate="{StaticResource DaybookItemDataTemplate}"
PreviewMouseDown="ItemListPopup_OnMouseButtonEvent"
MouseDown="ItemListPopup_OnMouseButtonEvent"
PreviewMouseMove="ItemListPopup_OnMouseEvent"
MouseMove="ItemListPopup_OnMouseEvent"
/>
</ListBoxItem>
</Popup>
<ContentPresenter x:Name="MyItemPresenter" ContentTemplate="{StaticResource DaybookItemDataTemplate}" ></ContentPresenter>
</StackPanel>
</DataTemplate>
Notice the events tied to both the ListBoxItem and the ContentPresenter within the Popup. They are tied to the following code-behind:
private void ItemListPopup_OnMouseButtonEvent(object sender, MouseButtonEventArgs e)
{
Popup popup = (((DependencyObject)sender).GetVisualParent<Popup>());
popup.PlacementTarget.RaiseEvent(e);
}
private void ItemListPopup_OnMouseEvent(object sender, MouseEventArgs e)
{
Popup popup = (((DependencyObject)sender).GetVisualParent<Popup>());
popup.PlacementTarget.RaiseEvent(e);
}
The PlacementTarget is the ListBoxItem that is being drawn over.
The MouseDown on the ContentPresenter is what allows the underlying ListViewItem to know it has been clicked and therefore selected, and that is working fine. The MouseDown on the ListBoxItem does not, against my expectations. (whether or not the ContentPresenter MouseDown event is hooked).
The other events seem to perform no useful task but I include them because I think they're an obvious thing to try.
I expected that relaying the MouseDown and MouseMove events to the underlying ListBox would allow it to detect a drag operation but it does not. I have also tried passing ALL mouse events in this way (tunnelling and bubbling) but drag operations still do not start.
The underlying control detects drag operations perfectly if the Popup is (permanently) disabled, however disabling the Popup within the mouse event does not help.
I have tried setting the Popup IsHitTestVisible to false but that doesn't help - I guess because the Popup is a separate Window and not part of the Visual Tree therefore there isn't anywhere for the events to bubble up to?
I have also tried changing the mouseEvent.Source but I get a runtime error "Cannot change the RoutedEvent property while the event is being routed". I tried to 'fake' a routed event but couldn't work out how to.
Any help appreciated. Oh and I'm new here so if I break etiquette please let me know.
This is connected with my previous question as it's dealt with the same piece of code; now that I've accomplished the changing of the background of the button, the problem is that now i need to implement the same code but not not for ButtonPressed but for clicked button. I've added click handlers in the code but it's not working - the background is not changing. I tried different approaches, even with using bitmaps and imagesources, but it's not working, the change simply does not happen. Now I want to implement the change of the background image but it needs to be done in the XAML file, not in the .cs . Again the code:
<Button x:Class="proba4.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="120" d:DesignWidth="300" IsEnabled="True">
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Image Name="Normal" Source="C:\stuff\off_button.gif"/>
<Image Name="Pressed" Source="C:\stuff\on_button.gif" Visibility="Hidden"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="Normal" Property="Visibility" Value="Hidden"/>
<Setter TargetName="Pressed" Property="Visibility" Value="Visible"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Template>
</Button>
Note that I've already looked for some button properties for clicking, but there was none, and all the implementations I've found on internet are dealing with adding Button_Click method in the .cs code of the control, and since that is not working for me, I need to find another way - hopefully something like fully implemented click control using WPF.
I guess this is delicate, but I will greatly appreciate any help with this, thanks.
It sounds like you want the behavior of a ToggleButton, not a Button. On Button clicking is a discrete event rather than a state that the control goes into that can be expressed by a property. A ToggleButton switches back and forth between two (or three) states when clicked, and the IsChecked property represents the state and can be bound in a Trigger like you're doing with IsPressed in your example.
Hello I am trying to make a textblock that they should focus on the event to underline the text and add when you lose the focus off him.
this is possible?
While I'm not sure if this is supported in Silverlight, this is how you'd do it in WPF:
<xxx.Resources>
<Style x:Key="HoverUnderline" TargetType="TextBlock">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="TextDecorations" Value="Underline"/>
</Trigger>
</Style.Triggers>
</Style>
...
<TextBlock Style="{StaticResource HoverUnderline}"
Content="Point at me to underline."/>
(Another interpretation of your question: use IsFocused instead of IsMouseOver. That's a weirder interpretation though since normally text blocks can't receive focus.)