How to recognize double clicks when closing WPF context menu - wpf

This is an example that highlights the problem:
<TextBlock Text="double click me" Width="150" Height="25"
ContextMenuOpening="TextBlock_ContextMenuOpening"
Mouse.MouseDown="TextBlock_MouseDown">
<TextBlock.ContextMenu>
<ContextMenu>
<MenuItem Header="test" />
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>
When the context menu is open, I double click the TextBlock. The first hit of TextBlock_MouseDown has e.ClickCount = 1 as expected, but so does the second. Is there any way I can get the clicks to be part of the same chain?

The first click closes the ContextMenu so you should be able to handle the ContextMenuClosing and then compare the total time elapsed between when the ContextMenu was closed and when the TextBlock was clicked again, e.g.:
DateTime dt;
private void TextBlock_MouseDown(object sender, MouseButtonEventArgs e)
{
if (DateTime.Now.Subtract(dt).TotalSeconds <= 0.3)
{
MessageBox.Show("double click detected!");
dt = DateTime.MinValue;
}
}
private void TextBlock_ContextMenuClosing(object sender, ContextMenuEventArgs e)
{
dt = DateTime.Now;
}
<TextBlock Text="double click me" Width="150" Height="25"
ContextMenuClosing="TextBlock_ContextMenuClosing"
Mouse.MouseDown="TextBlock_MouseDown">
<TextBlock.ContextMenu>
<ContextMenu>
<MenuItem Header="test" />
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>

How about using StaysOpenOnClick="True". You can close it after the double click:
<TextBlock Text="double click me" Width="150" Height="25" >
<TextBlock.ContextMenu>
<ContextMenu Name="cm">
<MenuItem PreviewMouseDoubleClick="MenuItem_PreviewMouseDoubleClick" Header="test"
StaysOpenOnClick="True" />
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>
in code:
private void MenuItem_PreviewMouseDoubleClick(object sender, MouseButtonEventArgs e)
{
// ...
cm.IsOpen = false;
}
Also note that there is a StaysOpen property in ContextMenu too, and you can use it.

Related

How to remove any formatting(bold, italic, fonts, font size) from a richtextbox WPF

I am making a text editor program in WPF and I need to make a Plain button, which it's purpose is to remove the formatting (bold, italic, font such as Arial, font size) of text of the RichTextBox.
This is my code so far:
<Window x:Class="TextEditor.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TextEditor"
Title="Text Editor" Height="480" Width="640">
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="_File" Name="Menu">
<MenuItem Header="New" Name="New"
Click="New_Click" />
<MenuItem Header="Save" Name="Save"
Click="Save_Click" />
</MenuItem>
</Menu>
<DockPanel DockPanel.Dock="Top">
<ToolBar>
<ToggleButton x:Name="boldButton"
ToolTip="Bold"
Command="{x:Static EditingCommands.ToggleBold}" CommandTarget="{Binding ElementName=_richTextBox}">
<Image Source="Icons/text_bold.png"
Height="25"
Width="25"/>
</ToggleButton>
<ToggleButton x:Name="italicButton"
ToolTip="Italic"
Command="{x:Static EditingCommands.ToggleItalic}" CommandTarget="{Binding ElementName=_richTextBox}">
<Image Source="Icons/text_italic.png"
Height="25"
Width="25"/>
</ToggleButton>
<ToggleButton x:Name="PlainButton"
ToolTip="Make the text plain"
Click="PlainButton_Click">
PlainText
</ToggleButton>
<Button x:Name="BackgroundButton"
ToolTip="Change the background of the textbox"
Click="BackgroundButton_Click">
Change the background
</Button>
<Separator/>
<ComboBox x:Name="fonts"
MinWidth="100"
DataContext="{x:Static Fonts.SystemFontFamilies}"
ItemsSource="{Binding}"
ToolTip="Font"
SelectionChanged="Font_SelectionChanged"/>
<ComboBox x:Name="fontSize"
MinWidth="40"
ToolTip="Font Size"
>
</ComboBox>
</ToolBar>
</DockPanel>
<StatusBar DockPanel.Dock="Bottom">
<TextBlock x:Name="status"/>
</StatusBar>
<RichTextBox x:Name="body"
FontSize="{Binding ElementName=fontSize, Path=SelectedItem}"
SpellCheck.IsEnabled="True"
AcceptsReturn="True"
AcceptsTab="True"
SelectionChanged="body_SelectionChanged"
BorderThickness="0 2 0 0"/>
</DockPanel>
</Window>
C sharp code:
public MainWindow()
{
InitializeComponent();
for (double i = 8; i <= 48; i += 2)
{
fontSize.Items.Add(i);
}
}
private void body_SelectionChanged(object sender, RoutedEventArgs e)
{
object temp = body.Selection.GetPropertyValue(Inline.FontFamilyProperty);
fonts.SelectedItem = temp;
}
private void New_Click(object sender, RoutedEventArgs e)
{
body.Document.Blocks.Clear();
}
private void Save_Click(object sender, RoutedEventArgs e)
{
SaveFileDialog sfd = new SaveFileDialog();
sfd.Filter = "Text file|*.txt";
sfd.FileName = "Untitled document";
if (sfd.ShowDialog() == true)
{
FileStream fileStream = new FileStream(sfd.FileName, FileMode.Create);
TextRange range = new TextRange(body.Document.ContentStart, body.Document.ContentEnd);
range.Save(fileStream, DataFormats.Text);
}
}
private void Font_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (fonts.SelectedItem != null)
body.Selection.ApplyPropertyValue(Inline.FontFamilyProperty, fonts.SelectedItem);
}
private void PlainButton_Click(object sender, RoutedEventArgs e)
{
//the code of the plain button
}
private void BackgroundButton_Click(object sender, RoutedEventArgs e)
{
body.Background = Brushes.Yellow;
}
It's a solution from 2009 ... I don't know if the richtext API in .NET has improved, but this post seems to have a solution for what you need.
Use the following code for WPF, if you are still looking for answers.
myRichTextBox.SelectAll();
myRichTextBox.Selection.ClearAllProperties();

How to subscribe event in datatemplate of listview

In WPF I have a listview that is bound to an ObservableCollection.
XAML:
<ListView Name="listView" DockPanel.Dock="Top" ItemsSource="{Binding Path=ListOfOldData}" SelectedItem="{Binding Path=SelectedOldData, Mode=TwoWay}" SelectionMode="Single">
<ListView.ContextMenu>
<ContextMenu>
<Button Content="Load" Command="{Binding Path=LoadCommand}" Name="loadButton" Height="23" Width="75" DockPanel.Dock="Left"/>
<!-- Is working just fine -->
</ContextMenu>
</ListView.ContextMenu>
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock MouseLeftButtonDown="TextBlock_MouseLeftButtonDown"
Text="{Binding Path=Name}" FontWeight="Bold"><TextBlock Text=" - " FontWeight="Normal"/><TextBlock Text="{Binding Path=UpdateDatum}" FontWeight="Normal"/></TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
What I actually wanted to receive is a double-click on the selected-item. As I can't bind a command to a textblock in xaml (can I?) I tried doing this via the MouseLeftButtonDown-Event. But the event is never received!
C# (in code behind):
private void TextBlock_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Console.WriteLine("MouseLeftButtonDown received!");
}
What am I doing wrong? How can I receive the event? Btw.: The command of the contextmenu is working just fine :)
UPDATE I found my error --> I added the event in the wrong usercontrol. Damn my missing concentration. Sorry for bugging you all.
you can simply use InvokeCommandAction from blend sdk (System.Windows.Interactivity.dll)
<ListView x:Name="lvw" ItemsSource="{Binding ListOfOldData}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<i:InvokeCommandAction Command="{Binding Path=OpenCommand}"
CommandParameter="{Binding ElementName=lvw, Path=SelectedItem}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ListView>
EDIT:
viewmodel should look something like this:
public List<object> ListOfOldData{ get; set; }
private DelegateCommand<object> _openCommand;//or RelayCommand
public DelegateCommand<object> OpenCommand
{
get { return _openCommand?? (this._openCommand= new DelegateCommand<object>(this.Execute)); }
}
private void Execute(object obj)
{
//obj is your selectedItem
}
ps: dunno your type thats why object
The ListView has a DoubleClick MouseEvent.
This should do it :
<ListView MouseDoubleClick="DoubleClickOnIt">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name}" FontWeight="Bold">
<TextBlock Text=" - " FontWeight="Normal"/>
<TextBlock Text="{Binding Path=UpdateDatum}" FontWeight="Normal"/>
</TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
<ListViewItem>
dddd
</ListViewItem>
<ListViewItem>
eeeee
</ListViewItem>
</ListView>
And the code behind :
private void DoubleClickOnIt(object sender, MouseButtonEventArgs e)
{
var listView = sender as ListView;
var selectedItem = listView.SelectedItem;
Console.WriteLine("received!");
}

How to open a popup menu when a button is clicked?

I have a button with an Image as its content in a toolbar. I would like this button to open a menu beneath it when clicked. How?
<Toolbar>
<Button>
<Button.Content>
<Image Source="../Resources/help.png"></Image>
</Button.Content>
</Button>
</Toolbar>
Thanks!!
Instead of using a subclassed Button, you can use Attached Properties or a Behavior to implement the drop down button functionality, for a more WPF-like approach and so you don't impact the button style:
using System.Windows.Interactivity;
public class DropDownButtonBehavior : Behavior<Button>
{
private bool isContextMenuOpen;
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.AddHandler(Button.ClickEvent, new RoutedEventHandler(AssociatedObject_Click), true);
}
void AssociatedObject_Click(object sender, System.Windows.RoutedEventArgs e)
{
Button source = sender as Button;
if (source != null && source.ContextMenu != null)
{
if (!isContextMenuOpen)
{
// Add handler to detect when the ContextMenu closes
source.ContextMenu.AddHandler(ContextMenu.ClosedEvent, new RoutedEventHandler(ContextMenu_Closed), true);
// If there is a drop-down assigned to this button, then position and display it
source.ContextMenu.PlacementTarget = source;
source.ContextMenu.Placement = PlacementMode.Bottom;
source.ContextMenu.IsOpen = true;
isContextMenuOpen = true;
}
}
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.RemoveHandler(Button.ClickEvent, new RoutedEventHandler(AssociatedObject_Click));
}
void ContextMenu_Closed(object sender, RoutedEventArgs e)
{
isContextMenuOpen = false;
var contextMenu = sender as ContextMenu;
if (contextMenu != null)
{
contextMenu.RemoveHandler(ContextMenu.ClosedEvent, new RoutedEventHandler(ContextMenu_Closed));
}
}
}
Usage:
<!-- NOTE: xmlns:i="schemas.microsoft.com/expression/2010/interactivity‌​" -->
<Button>
<i:Interaction.Behaviors>
<local:DropDownButtonBehavior/>
</i:Interaction.Behaviors>
<Button.Content>
<StackPanel Orientation="Horizontal">
<Image Source="/DropDownButtonExample;component/Assets/add.png" SnapsToDevicePixels="True" Height="16" Width="16" />
<TextBlock Text="Add"/>
<Separator Margin="2,0">
<Separator.LayoutTransform>
<TransformGroup>
<TransformGroup.Children>
<TransformCollection>
<RotateTransform Angle="90"/>
</TransformCollection>
</TransformGroup.Children>
</TransformGroup>
</Separator.LayoutTransform>
</Separator>
<Path Margin="2" VerticalAlignment="Center" Width="6" Fill="#FF527DB5" Stretch="Uniform" HorizontalAlignment="Right" Data="F1 M 301.14,-189.041L 311.57,-189.041L 306.355,-182.942L 301.14,-189.041 Z "/>
</StackPanel>
</Button.Content>
<Button.ContextMenu>
<ContextMenu>
<MenuItem Header="Attribute"/>
<MenuItem Header="Setting"/>
<Separator/>
<MenuItem Header="Property"/>
</ContextMenu>
</Button.ContextMenu>
</Button>
Current gist source and example here.
If you have the luxury of targeting .NET 4 or newer, the new Ribbon library has a RibbonMenuButton that can do this. In 4.5 it is as easy as referencing System.Windows.Controls.Ribbon in your project:
<RibbonMenuButton x:Name="ExampleMenu" SmallImageSource="/Images/Example.png">
<RibbonMenuItem x:Name="ExampleMenuItem" Header="Save" />
</RibbonMenuButton>
i found this two solutions after searching for it:
1) Split Button in WPF
2) DropDownButtons in WPF
the second solution is my favorit (source taken from the website by Andrew Wilkinson)
public class DropDownButton : ToggleButton
{
// *** Dependency Properties ***
public static readonly DependencyProperty DropDownProperty =
DependencyProperty.Register("DropDown",
typeof(ContextMenu),
typeof(DropDownButton),
new UIPropertyMetadata(null));
// *** Constructors ***
public DropDownButton() {
// Bind the ToogleButton.IsChecked property to the drop-down's IsOpen property
Binding binding = new Binding("DropDown.IsOpen");
binding.Source = this;
this.SetBinding(IsCheckedProperty, binding);
}
// *** Properties ***
public ContextMenu DropDown {
get { return (ContextMenu)this.GetValue(DropDownProperty); }
set { this.SetValue(DropDownProperty, value); }
}
// *** Overridden Methods ***
protected override void OnClick() {
if (this.DropDown != null) {
// If there is a drop-down assigned to this button, then position and display it
this.DropDown.PlacementTarget = this;
this.DropDown.Placement = PlacementMode.Bottom;
this.DropDown.IsOpen = true;
}
}
}
usage
<ctrl:DropDownButton Content="Drop-Down">
<ctrl:DropDownButton.DropDown>
<ContextMenu>
<MenuItem Header="Item 1" />
<MenuItem Header="Item 2" />
<MenuItem Header="Item 3" />
</ContextMenu>
</ctrl:DropDownButton.DropDown>
</ctrl:DropDownButton>
hope that helps you...
There are lots of ways to get this done and you might consider this approach...
<ToolBar DockPanel.Dock="Top">
<MenuItem IsSubmenuOpen="{Binding SomeProperty}">
<MenuItem.Header>
<Button Height="28">
<Button.Content>
<Image Source="---your image---"></Image>
</Button.Content>
</Button>
</MenuItem.Header>
<Menu>
<MenuItem Header="Do this" />
<MenuItem Header="Do that"/>
</Menu>
</MenuItem>
</ToolBar>
This wraps your button into a MenuItem that has a submenu. As shown here, the MenuItem property called IsSubMenuOpen is bound to a notifying property of type bool in your ViewModel called SomeProperty.
You would have to have your ViewModel toggle this property depending upon what you are actually trying to do. You may want to consider making your button a toggle button so as to facilitate closing the submenu, otherwise you'll have to wire up additional behaviour in your ViewModel.

ListBox with hyperlink -> selection changed

I want to do with xaml bindings such feature:
Listbox contains hyperlinks.
When hyperlink clicked - we go to another frame
But also SelectedItem must changed, and on another frame we show info about selected item.
I want it without subscribing click/selected events. Only declarative
Example of my listbox
<ListBox Grid.Row="1"
x:Name="OrderTypesListBox"
ItemsSource="{Binding OrderTypes, Mode=OneWay}"
SelectedItem="{Binding SelectedCall.OrderType, Mode=TwoWay}"
>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Name}" />
<HyperlinkButton Style="{StaticResource LinkStyle}" NavigateUri="/WindowPage" TargetName="ContentFrame" Content="WindowPage"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Now solve like that
<ListBox Grid.Row="1"
x:Name="OrderTypesListBox"
ItemsSource="{Binding OrderTypes, Mode=OneWay}"
SelectedItem="{Binding SelectedCall.OrderType, Mode=TwoWay}"
>
<ListBox.ItemTemplate>
<DataTemplate>
<HyperlinkButton
TargetName="ContentFrame"
NavigateUri="{Binding OrderTypeNextPage}"
Content="{Binding Name}"
Click="HyperlinkButton_Click"
Tag="{Binding}"
/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
private void HyperlinkButton_Click(object sender, RoutedEventArgs e)
{
OrderTypesListBox.SelectedItem = (sender as HyperlinkButton).Tag;
}
Don't use a HyperlinkButton. Perform the needed actions when the SelectedItem changes in your ViewModel.
Edit: If you need to respond to all click events even if the item is already selected then you can use a Behavior to do this. Just create a behavior for the TextBlock that navigates on the TextBlock click event.
Edit2: Behaviors are pretty simple to code up and easy to use (and don't break the MVVM paradigm).
public class NavigatingTextBlockBehavior : Behavior<TextBlock>
{
protected override void OnAttached()
{
AssociatedObject.MouseLeftButtonDown += new MouseButtonEventHandler(OnMouseDown);
}
private void OnMouseDown(object sender, MouseButtonEventArgs e)
{
NavigationService.Navigate(new Uri("/WindowPage"));
}
}

WPF and initial focus

It seems that when a WPF application starts, nothing has focus.
This is really weird. Every other framework I've used does just what you'd expect: puts initial focus on the first control in the tab order. But I've confirmed that it's WPF, not just my app -- if I create a new Window, and just put a TextBox in it, and run the app, the TextBox doesn't have focus until I click on it or press Tab. Yuck.
My actual app is more complicated than just a TextBox. I have several layers of UserControls within UserControls. One of those UserControls has Focusable="True" and KeyDown/KeyUp handlers, and I want it to have the focus as soon as my window opens. I'm still somewhat of a WPF novice, though, and I'm not having much luck figuring out how to do this.
If I start my app and press the Tab key, then focus goes to my focusable control, and it starts working the way I want. But I don't want my users to have to hit Tab before they can start using the window.
I've played around with FocusManager.FocusedElement, but I'm not sure which control to set it on (the top-level Window? the parent that contains the focusable control? the focusable control itself?) or what to set it to.
What do I need to do to get my deeply-nested control to have initial focus as soon as the window opens? Or better yet, to focus the first focusable control in the tab order?
This works, too:
<Window FocusManager.FocusedElement="{Binding ElementName=SomeElement}">
<DataGrid x:Name="SomeElement">
...
</DataGrid>
</Window>
I had the bright idea to dig through Reflector to see where the Focusable property is used, and found my way to this solution. I just need to add the following code to my Window's constructor:
Loaded += (sender, e) =>
MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
This will automatically select the first control in the tab order, so it's a general solution that should be able to be dropped into any window and Just Work.
Based on the accepted answer implemented as an attached behavior:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace UI.Behaviors
{
public static class FocusBehavior
{
public static readonly DependencyProperty FocusFirstProperty =
DependencyProperty.RegisterAttached(
"FocusFirst",
typeof(bool),
typeof(FocusBehavior),
new PropertyMetadata(false, OnFocusFirstPropertyChanged));
public static bool GetFocusFirst(Control control)
{
return (bool)control.GetValue(FocusFirstProperty);
}
public static void SetFocusFirst (Control control, bool value)
{
control.SetValue(FocusFirstProperty, value);
}
static void OnFocusFirstPropertyChanged(
DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
Control control = obj as Control;
if (control == null || !(args.NewValue is bool))
{
return;
}
if ((bool)args.NewValue)
{
control.Loaded += (sender, e) =>
control.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
}
}
}
}
Use it like this:
<Window xmlns:Behaviors="clr-namespace:UI.Behaviors"
Behaviors:FocusBehavior.FocusFirst="true">
I found another possible solution. Mark Smith posted a FirstFocusedElement markup extension for use with FocusManager.FocusedElement.
<UserControl x:Class="FocusTest.Page2"
xmlns:FocusTest="clr-namespace:FocusTest"
FocusManager.FocusedElement="{FocusTest:FirstFocusedElement}">
After having a 'WPF Initial Focus Nightmare' and based on some answers on stack, the following proved for me to be the best solution.
First, add your App.xaml OnStartup() the followings:
EventManager.RegisterClassHandler(typeof(Window), Window.LoadedEvent,
new RoutedEventHandler(WindowLoaded));
Then add the 'WindowLoaded' event also in App.xaml :
void WindowLoaded(object sender, RoutedEventArgs e)
{
var window = e.Source as Window;
System.Threading.Thread.Sleep(100);
window.Dispatcher.Invoke(
new Action(() =>
{
window.MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
}));
}
The threading issue must be use as WPF initial focus mostly fails due to some framework race conditions.
I found the following solution best as it is used globally for the whole app.
Hope it helps...
Oran
Had same problem solved it with simple solution:
In the main window:
<Window ....
FocusManager.FocusedElement="{Binding ElementName=usercontrolelementname}"
... />
In the user control:
private void UserControl_GotFocus_1(object sender, RoutedEventArgs e)
{
targetcontrol.Focus();
this.GotFocus -= UserControl_GotFocus_1; // to set focus only once
}
You can easily have the control set itself as the focused element in XAML.
<Window>
<DataGrid FocusManager.FocusedElement="{Binding RelativeSource={RelativeSource Self}}">
...
</DataGrid>
</Window>
I've never tried setting this in a usercontrol and seeing if this works, but it may.
A minimal version of Mizipzor's answer for C# 6+.
public static class FocusBehavior
{
public static readonly DependencyProperty GiveInitialFocusProperty =
DependencyProperty.RegisterAttached(
"GiveInitialFocus",
typeof(bool),
typeof(FocusBehavior),
new PropertyMetadata(false, OnFocusFirstPropertyChanged));
public static bool GetGiveInitialFocus(Control control) => (bool)control.GetValue(GiveInitialFocusProperty);
public static void SetGiveInitialFocus(Control control, bool value) => control.SetValue(GiveInitialFocusProperty, value);
private static void OnFocusFirstPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
var control = obj as Control;
if (control == null || !(args.NewValue is bool))
return;
if ((bool)args.NewValue)
control.Loaded += OnControlLoaded;
else
control.Loaded -= OnControlLoaded;
}
private static void OnControlLoaded(object sender, RoutedEventArgs e) => ((Control)sender).MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
}
Use in your XAML:
<Window local:FocusBehavior.GiveInitialFocus="True" />
Above solution was not working as expected for me, I've changed slightly the behavior proposed by Mizipzor as following:
From this part
if ((bool)args.NewValue)
{
control.Loaded += (sender, e) =>
control.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
}
To this
if ((bool)args.NewValue)
{
control.Loaded += (sender, e) => control.Focus();
}
ANd I'm not attaching this behavior to Window or UserControl, but to control I want to focus initially, e.g.:
<TextBox ui:FocusBehavior.InitialFocus="True" />
Oh, sorry for different naming I'm using InitialFocus name for the attached property.
And this is working for me, maybe it could help someone else.
If you are like me, and you are using some frameworks that, somehow, mess up with the basic focus behaviors, and make all solutions above irrelevant, you can still do this :
1 - Note the element which get the focus (whatever it is!)
2 - Add this in your code behind xxx.xaml.cs
private bool _firstLoad;
3 - Add this on the element which get the first focus :
GotFocus="Element_GotFocus"
4 - Add the Element_GotFocus method in the code behind, and specify the WPF named element who need the first focus :
private void Element_GotFocus(object sender, RoutedEventArgs e)
{
if(_firstLoad)
{
this.MyElementWithFistFocus.Focus();
_firstLoad = false;
}
}
5 - Manage the Loaded event
in XAML
Loaded="MyWindow_Loaded"
in xaml.cs
private void MyWindow_Loaded(object sender, RoutedEventArgs e)
{
_firstLoad = true;
this.Element_GotFocus(null, null);
}
Hope this will help as a last resort solution
I also faced the same problem. I had three text boxes inside canvas container and wanted the first text box to be focused when the user control opens. WPF code followed MVVM pattern. I created a separate behavior class for focusing the element and binded it to my view like this.
Canvas behavior code
public class CanvasLoadedBehavior : Behavior<Canvas>
{
private Canvas _canvas;
protected override void OnAttached()
{
base.OnAttached();
_canvas = AssociatedObject as Canvas;
if (_canvas.Name == "ReturnRefundCanvas")
{
_canvas.Loaded += _canvas_Loaded;
}
}
void _canvas_Loaded(object sender, RoutedEventArgs e)
{
FocusNavigationDirection focusDirection = FocusNavigationDirection.Next;
// MoveFocus takes a TraveralReqest as its argument.
TraversalRequest request = new TraversalRequest(focusDirection);
UIElement elementWithFocus = Keyboard.FocusedElement as UIElement;
if (elementWithFocus != null)
{
elementWithFocus.MoveFocus(request);
}
}
}
Code for view
<Canvas Name="ReturnRefundCanvas" Height="200" Width="1466" DataContext="{Binding RefundSearchViewModel}">
<i:Interaction.Behaviors>
<b:CanvasLoadedBehavior />
</i:Interaction.Behaviors>
<uc:Keyboard Canvas.Left="973" Canvas.Top="111" ToolTip="Keyboard" RenderTransformOrigin="-2.795,9.787"></uc:Keyboard>
<Label Style="{StaticResource Devlbl}" Canvas.Left="28" Content="Return and Refund Search" Canvas.Top="10" />
<Image Height="30" Width="28" Canvas.Top="6" Canvas.Left="5" Source="pack://application:,,,/HomaKiosk;component/images/searchF.png">
<Image.OpacityMask>
<ImageBrush ImageSource="pack://application:,,,/HomaKiosk;component/images/searchF.png"/>
</Image.OpacityMask>
</Image>
<Separator Height="4" Canvas.Left="6" Margin="0" Canvas.Top="35" Width="1007"/>
<ContentControl Canvas.Top="45" Canvas.Left="21"
ContentTemplate="{StaticResource ErrorMsg}"
Visibility="{Binding Error, Converter={c:StringNullOrEmptyToVisibilityConverter}}"
Content="{Binding Error}" Width="992"></ContentControl>
<Label Style="{StaticResource Devlbl}" Canvas.Left="29" Name="FirstName" Content="First Name" Canvas.Top="90" />
<wpf:AutoCompleteTextBox Style="{StaticResource AutoComp}" Height="32" Canvas.Left="33" ToolTip="First Name" Canvas.Top="120" Width="205" Padding="10,5" TabIndex="1001"
VerticalAlignment="Top"
Watermark=""
IconPlacement="Left"
IconVisibility="Visible"
Delay="100"
Text="{Binding FirstName, Mode=TwoWay, TargetNullValue=''}"
Provider="{Binding FirstNameSuggestions}">
<wpf:AutoCompleteTextBox.ItemTemplate>
<DataTemplate>
<Border Padding="5">
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding}"
FontWeight="Bold" />
</StackPanel>
</Border>
</DataTemplate>
</wpf:AutoCompleteTextBox.ItemTemplate>
</wpf:AutoCompleteTextBox>
<Label Style="{StaticResource Devlbl}" Canvas.Left="250" Content="Last Name" Canvas.Top="90" />
<wpf:AutoCompleteTextBox Style="{StaticResource AutoComp}" Height="32" ToolTip="Last Name" Canvas.Left="250" Canvas.Top="120" Width="205" Padding="10,5" TabIndex="1002"
VerticalAlignment="Top"
Watermark=""
IconPlacement="Left"
IconVisibility="Visible"
Delay="100"
Text="{Binding LastName, Mode=TwoWay, TargetNullValue=''}"
Provider="{Binding LastNameSuggestions}">
<wpf:AutoCompleteTextBox.ItemTemplate>
<DataTemplate>
<Border Padding="5">
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding}"
FontWeight="Bold" />
</StackPanel>
</Border>
</DataTemplate>
</wpf:AutoCompleteTextBox.ItemTemplate>
</wpf:AutoCompleteTextBox>
<Label Style="{StaticResource Devlbl}" Canvas.Left="480" Content="Receipt No" Canvas.Top="90" />
<wpf:AutoCompleteTextBox Style="{StaticResource AutoComp}" Height="32" ToolTip="Receipt No" Canvas.Left="480" Canvas.Top="120" Width="205" Padding="10,5" TabIndex="1002"
VerticalAlignment="Top"
Watermark=""
IconPlacement="Left"
IconVisibility="Visible"
Delay="100"
Text="{Binding ReceiptNo, Mode=TwoWay, TargetNullValue=''}"
Provider="{Binding ReceiptIdSuggestions}">
<wpf:AutoCompleteTextBox.ItemTemplate>
<DataTemplate>
<Border Padding="5">
<StackPanel Orientation="Vertical" >
<TextBlock Text="{Binding}"
FontWeight="Bold">
</TextBlock>
</StackPanel>
</Border>
</DataTemplate>
</wpf:AutoCompleteTextBox.ItemTemplate>
<i:Interaction.Behaviors>
<b:AllowableCharactersTextBoxBehavior RegularExpression="^[0-9]+$" MaxLength="15" />
</i:Interaction.Behaviors>
</wpf:AutoCompleteTextBox>
<!--<Label Style="{StaticResource Devlbl}" Canvas.Left="710" Content="Duration" Canvas.Top="79" />-->
<!--<ComboBox AllowDrop="True" Canvas.Left="710" ToolTip="Duration" Canvas.Top="107" Width="205" TabIndex="1004"
Style="{StaticResource CommonComboBox}"
ItemsSource="{Binding Durations}" DisplayMemberPath="Description" SelectedValuePath="Id" SelectedValue="{Binding SelectedDate, Mode=TwoWay}">
</ComboBox>-->
<Button Content="Search" Style="{StaticResource MyButton}" ToolTip="Search"
Canvas.Top="116" Canvas.Left="710" Cursor="Hand"
Command="{Binding SearchCommand}" TabIndex="2001">
</Button>
<Button Content="Clear" Style="{StaticResource MyButton}" ToolTip="Clear"
Canvas.Top="116" Canvas.Left="840" Cursor="Hand"
Command="{Binding ClearCommand}" TabIndex="2002">
</Button>
<Image Height="25" Width="25" Canvas.Top="175" Canvas.Left="25" Source="pack://application:,,,/HomaKiosk;component/images/chkpending.png"/>
<Label Style="{StaticResource LegendLbl}" Canvas.Left="50" Content="Check Returned and Payment Pending" Canvas.Top="178" />
<Image Height="25" Width="25" Canvas.Top="175" Canvas.Left="300" Source="pack://application:,,,/HomaKiosk;component/images/chkrepaid.png"/>
<Label Style="{StaticResource LegendLbl}" Canvas.Left="325" Content="Repaid" Canvas.Top="178" />
<Image Height="25" Width="25" Canvas.Top="175" Canvas.Left="395" Source="pack://application:,,,/HomaKiosk;component/images/refund.png"/>
<Label Style="{StaticResource LegendLbl}" Canvas.Left="415" Content="Refunded" Canvas.Top="178" />
</Canvas>
<Window FocusManager.FocusedElement="{Binding ElementName=yourControlName}">

Resources