WPF ListBox grow up on Event Handler? - wpf

I am extremely new using C# and that's far away from my mechanical skills ... I have very basic knowledge in C# but I am really willing to push the knowledge effort. Thanks to keep it in minde.
I creating some sort of application/ERP to help with working with my suppliers. The final goal is to create a list of suppliers, their skills, consult RFQ, update RFQ, send emails, ... I have been doing it in Excel VBA in the past but now I am willing to build up something stronger (and also willing to learn something new ...).
First of all, I am willing to create a ListBox with different kind of processes. I would like this ListBox to only show one ListBoxItems (one row) and when the mouse is entering into the ListBox, grow the ListBox to it's full size.
(My goal would be to ! create a ListBox with a dropdown for multiselection :=))
The dirty way I was thinking doing it is:
Create a TextBox with "Click to expand" text. When the mouse is entering the Textbox, hide it and change the listbox visibility to Visible (default visibility to Hidde);
Any thought about it ? Where should I start by ?
I will then selected multiple items in my ListBox.
Latter on, I would like to binding ListBox content to a data base (don't know how to create it on my computer).
Any help is greatly appreciated !
Cheers
Edit:
Below is my XAML code:
<Window x:Class="ERP_Fournisseurs.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ERP_Fournisseurs"
mc:Ignorable="d"
Title="ERP Fournisseurs" Height="450" Width="800">
<Canvas>
<TabControl Height="369" Width="734" Canvas.Left="10" Canvas.Top="9">
<TabItem Header="Ajouter fournisseurs">
<Canvas Margin="0,0,0,-1">
<TextBlock Canvas.Left="10" Name="Fournisseur" TextWrapping="Wrap" Text="Nom fournisseur" Canvas.Top="16" />
<TextBox Height="23" Name="NomTXT" Canvas.Left="150" TextWrapping="Wrap" Text="Entrer nom fournisseur" Canvas.Top="14" Width="225" MouseDoubleClick="NomFournisseur_MouseDoubleClick" TextChanged="NomTXT_TextChanged" />
<TextBlock Canvas.Left="10" Name="Telephone" TextWrapping="Wrap" Text="Telephone" Canvas.Top="55"/>
<TextBox Height="23" Name="TelTXT" Canvas.Left="150" TextWrapping="Wrap" Text="Entrer téléphone fournisseur" Canvas.Top="55" Width="225" MouseDoubleClick="TelTXT_MouseDoubleClick"/>
<TextBlock Canvas.Left="10" Name="Mail" TextWrapping="Wrap" Text="Mail" Canvas.Top="84"/>
<TextBox Height="23" Name="MailTXT" Canvas.Left="150" TextWrapping="Wrap" Text="Entrer adresse e-mail" Canvas.Top="91" Width="225" MouseDoubleClick="MailTXT_MouseDoubleClick"/>
<TextBlock Canvas.Left="10" Name="Adresse" TextWrapping="Wrap" Text="Adresse" Canvas.Top="124"/>
<TextBox Height="23" Name="AdresseTXT" Canvas.Left="150" TextWrapping="Wrap" Text="Entrer adresse" Canvas.Top="127" Width="225" MouseDoubleClick="AdresseTXT_MouseDoubleClick"/>
<TextBlock Canvas.Left="10" Name="Types" TextWrapping="Wrap" Text="Types" Canvas.Top="157"/>
<TextBox Height="23" Name="TypesTXT" Canvas.Left="150" TextWrapping="Wrap" Text="Entrer types" Canvas.Top="162" Width="225" />
<TextBlock Canvas.Left="10" Name="Procédés" TextWrapping="Wrap" Text="Procédés" Canvas.Top="194"/>
<TextBlock Canvas.Left="10" Name="Matériaux" TextWrapping="Wrap" Text="Matériaux" Canvas.Top="232"/>
<TextBlock Canvas.Left="10" Name="Délais" TextWrapping="Wrap" Text="Délais" Canvas.Top="258"/>
<TextBlock Canvas.Left="10" Name="Autres" TextWrapping="Wrap" Text="Autres" Canvas.Top="289"/>
<TextBox Height="23" x:Name="AutreTXT" Canvas.Left="150" TextWrapping="Wrap" Text="Entrer types" Canvas.Top="289" Width="225" MouseDoubleClick="AutreTXT_MouseDoubleClick"/>
<Button Name="AjoutTXT" Content="Ajouter" Height="100" Width="75" Canvas.Left="563" Canvas.Top="107" Click="AjoutTXT_Click"/>
<ListBox Name="ListBoxProc" HorizontalAlignment="Left" VerticalAlignment="Top" Width="181" Height="186" Canvas.Left="409" Canvas.Top="54" Visibility="Hidden" MouseLeave="ListBoxProc_MouseLeave" MouseEnter="ListBoxProc_MouseEnter" SelectionMode="Multiple">
<ListBoxItem>TEST 1</ListBoxItem>
<ListBoxItem>TEST 1</ListBoxItem>
<ListBoxItem>TEST 1</ListBoxItem>
<ListBoxItem>TEST 1</ListBoxItem>
</ListBox>
<TextBox Height="23" Name="ProcTXT2" Canvas.Left="150" TextWrapping="Wrap" Text="Entrer types" Canvas.Top="196" Width="225" />
</Canvas>
</TabItem>
<TabItem Header="Suivi devis" >
<Canvas>
</Canvas>
</TabItem>
<TabItem Header="Liste fournisseurs" >
<Canvas>
</Canvas>
</TabItem>
</TabControl>
</Canvas>
</Window>
Below is my XAML.CS
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace ERP_Fournisseurs
{
/// <summary>
/// Logique d'interaction pour MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void NomFournisseur_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
NomTXT.Text = "";
}
private void TelTXT_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
TelTXT.Text = "";
}
private void MailTXT_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
MailTXT.Text = "";
}
private void AdresseTXT_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
AdresseTXT.Text = "";
}
private void AjoutTXT_Click(object sender, RoutedEventArgs e)
{
}
private void AutreTXT_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
AutreTXT.Text = "";
}
private void ProcTXT_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
}
private void NomTXT_TextChanged(object sender, TextChangedEventArgs e)
{
}
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
}
private void MaterTXT_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
}
private void ProcTXT_MouseEnter(object sender, MouseEventArgs e)
{
}
private void ListBoxProc_MouseEnter(object sender, MouseEventArgs e)
{
ListBoxProc.Visibility = Visibility.Hidden;
}
private void ListBoxProc_MouseLeave(object sender, MouseEventArgs e)
{
ListBoxProc.Visibility = Visibility.Visible;
}
//https://www.c-sharpcorner.com/UploadFile/mahesh/listbox-in-wpf/ Binding ListBox to Data Base
}
}
What I have tried:
Asked google my solution, but it's answerless;
Tried the following code (https://www.codeproject.com/Questions/696480/How-to-make-a-ListBox-grow-on-mouseover) but not working

Related

UWP - Interception of pointer events by parent control (where child is ScrollViewer)

I'm looking for an approach to how I can intercept all events like PointerReleased by a parent.
My issue is that I can't intercept the ScrollViewer's parent PointerReleased event.
I want to put a finger (cursor) into the ScrollViewer move over for 100px with my finger and then release it; it should work as if Scrollviewer.IsHitTestVisible=false and receive all events to outerStack (scrollerviewer's parent), but scrollviewer should work as if IsHitTestVisible=true and continue to get all related events to itself (scrollviewer) and its children (scrollviewer children like innerStack).
I am getting the following log
innerStack_PointerPressed
scrollView_PointerPressed
outerStack_PointerPressed
CoreWindow_PointerPressed
But I'm expecting to see this one
innerStack_PointerPressed
scrollView_PointerPressed
outerStack_PointerPressed
CoreWindow_PointerPressed
outerStack_PointerReleased
CoreWindow_PointerReleased
There is a code example
<Page
x:Class="App9.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel x:Name="outerStack"
Background="Red"
Padding="40"
PointerPressed="outerStack_PointerPressed"
PointerReleased="outerStack_PointerReleased">
<ScrollViewer x:Name="scrollView"
Background="Blue"
Padding="40"
PointerPressed="scrollView_PointerPressed"
PointerReleased="scrollView_PointerReleased"
VerticalScrollBarVisibility="Visible"
VerticalScrollMode="Enabled"
HorizontalScrollBarVisibility="Visible"
HorizontalScrollMode="Enabled"
Height="500">
<StackPanel x:Name="innerStack"
Background="Green"
Padding="40"
PointerPressed="innerStack_PointerPressed"
PointerReleased="innerStack_PointerReleased">
<TextBlock Text="A" FontSize="100"/>
<TextBlock Text="B" FontSize="100"/>
<TextBlock Text="C" FontSize="100"/>
<TextBlock Text="D" FontSize="100"/>
<TextBlock Text="E" FontSize="100"/>
<TextBlock Text="F" FontSize="100"/>
<TextBlock Text="G" FontSize="100"/>
<TextBlock Text="H" FontSize="100"/>
<TextBlock Text="I" FontSize="100"/>
<TextBlock Text="J" FontSize="100"/>
<TextBlock Text="K" FontSize="100"/>
<TextBlock Text="L" FontSize="100"/>
<TextBlock Text="M" FontSize="100"/>
<TextBlock Text="N" FontSize="100"/>
<TextBlock Text="O" FontSize="100"/>
<TextBlock Text="P" FontSize="100"/>
<TextBlock Text="Q" FontSize="100"/>
<TextBlock Text="R" FontSize="100"/>
<TextBlock Text="S" FontSize="100"/>
<TextBlock Text="T" FontSize="100"/>
<TextBlock Text="U" FontSize="100"/>
<TextBlock Text="V" FontSize="100"/>
<TextBlock Text="W" FontSize="100"/>
<TextBlock Text="X" FontSize="100"/>
<TextBlock Text="Y" FontSize="100"/>
<TextBlock Text="Z" FontSize="100"/>
</StackPanel>
</ScrollViewer>
</StackPanel>
</Page>
using System.Diagnostics;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
namespace App9
{
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
Window.Current.CoreWindow.PointerPressed += CoreWindow_PointerPressed;
Window.Current.CoreWindow.PointerReleased += CoreWindow_PointerReleased;
}
private void CoreWindow_PointerPressed(Windows.UI.Core.CoreWindow sender, Windows.UI.Core.PointerEventArgs args)
{
Debug.WriteLine("CoreWindow_PointerPressed");
}
private void CoreWindow_PointerReleased(Windows.UI.Core.CoreWindow sender, Windows.UI.Core.PointerEventArgs args)
{
Debug.WriteLine("CoreWindow_PointerReleased");
}
private void outerStack_PointerPressed(object sender, PointerRoutedEventArgs e)
{
Debug.WriteLine("outerStack_PointerPressed");
}
private void outerStack_PointerReleased(object sender, PointerRoutedEventArgs e)
{
Debug.WriteLine("outerStack_PointerReleased");
}
private void scrollView_PointerPressed(object sender, PointerRoutedEventArgs e)
{
Debug.WriteLine("scrollView_PointerPressed");
}
private void scrollView_PointerReleased(object sender, PointerRoutedEventArgs e)
{
Debug.WriteLine("scrollView_PointerReleased");
}
private void innerStack_PointerPressed(object sender, PointerRoutedEventArgs e)
{
Debug.WriteLine("innerStack_PointerPressed");
}
private void innerStack_PointerReleased(object sender, PointerRoutedEventArgs e)
{
Debug.WriteLine("innerStack_PointerReleased");
}
}
}
The simplest solution is to put the next property to the content view of ScrollViewer
ScrollViewer.Content.ManipulationMode="TranslateX,System"
The solution is not perfect, but it's simple.
More info https://learn.microsoft.com/ru-ru/archive/blogs/wsdevsol/where-did-all-my-gestures-go
My issue is that I can't intercept the ScrollViewer's parent PointerReleased event.
Please refer to Events and routed events overview document, and
Setting the Handled property to true influences the event system behavior. When Handled is true, the routing stops for most event handlers; the event doesn't continue along the route to notify other attached handlers of that particular event case.
So you could set scrollview's PointerReleased Handled as true
private void scrollView_PointerPressed(object sender, PointerRoutedEventArgs e)
{
Debug.WriteLine("scrollView_PointerPressed");
e.Handled = true;
}
private void scrollView_PointerReleased(object sender, PointerRoutedEventArgs e)
{
Debug.WriteLine("scrollView_PointerReleased");
e.Handled = true;
}

How to make a collapsed tab item visible programmatically in WPF?

how do i make a collapsed tab item visible programmatically in WPF?
I have created a xaml file with a tabcontrol with three tabs, the visibility property I have set succesively to Visible. Hidden and Collapsed. Also I have two buttons one to set Tab 2 to visible and the other to set Tab 3 to visible.
In the code behind I have set up an event handler for each button.
The event handlers don't compile.
I would appreciate any suggestions . Thanks!
Here is my MainWindow.xaml
<Window x:Class="WPFTabItemVisibility.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<TabControl>
<TabItem Header="Tab 1" Visibility="Visible" Content="Tab 1 Content goes here"></TabItem>
<TabItem Header="Tab 2" Visibility="Hidden" Content="Tab 2 Content goes here"></TabItem>
<TabItem Header="Tab 3" Visibility="Collapsed" Content="Tab 3 Content goes here"></TabItem>
</TabControl>
<Button Content="Make Tab 2 Visible" Margin="20" Height="30" Width="200" Click="Button_Click"/>
<Button Content="Make Tab 3 Visible" Margin="20" Height="30" Width="200" Click="Button_Click_1"/>
</StackPanel>
</Window>
here is my MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WPFTabItemVisibility
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
TabIndex = 1;
TabItem.VisibilityProperty = IsVisible;
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
TabIndex = 2;
TabItem.VisibilityProperty = IsVisible;
}
}
}
Thank you!
You can give name to the tabitem and set its visibility. Refer the below code.
<TabControl>
<TabItem x:Name="tab1" Header="Tab 1" Visibility="Visible" Content="Tab 1 Content goes here"></TabItem>
<TabItem x:Name="tab2" Header="Tab 2" Visibility="Hidden" Content="Tab 2 Content goes here"></TabItem>
<TabItem x:Name="tab3" Header="Tab 3" Visibility="Collapsed" Content="Tab 3 Content goes here"></TabItem>
</TabControl>
private void Button_Click(object sender, RoutedEventArgs e)
{
tab2.Visibility = Visibility.Visible;
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
tab3.Visibility = Visibility.Visible;
}
try this in your XAML
<StackPanel>
<TabControl>
<TabItem Header="Tab 1"
Visibility="Visible"
Name="tab1"
Content="Tab 1 Content goes here"></TabItem>
<TabItem Header="Tab 2"
Visibility="Hidden"
Name="tab2"
Content="Tab 2 Content goes here"></TabItem>
<TabItem Header="Tab 3"
Name="tab3"
Visibility="Collapsed"
Content="Tab 3 Content goes here"></TabItem>
</TabControl>
<Button Content="Make Tab 2 Visible"
Margin="20"
Height="30"
Width="200"
Click="Button_Click" />
<Button Content="Make Tab 3 Visible"
Margin="20"
Height="30"
Width="200"
Click="Button_Click_1" />
</StackPanel>
CodeBehind .cs File
private void Button_Click(object sender, RoutedEventArgs e)
{
//TabIndex = 1;
//TabItem.VisibilityProperty = IsVisible;
tab2.Visibility = Visibility.Visible;
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
//TabIndex = 2;
//TabItem.VisibilityProperty = IsVisible;
tab3.Visibility = Visibility.Visible;
}

MVVM code for a calculator in WPF

I've written a code for a simple calculator in wpf .
My MainWindow.Xaml code is..
<Window x:Class="CalculatorNew.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid ContextMenuClosing="Multi">
<TextBox x:Name="TextBox1" HorizontalAlignment="Left" Height="23" Margin="216,23,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" RenderTransformOrigin="0.679,0.552"/>
<TextBox x:Name="TextBox2" HorizontalAlignment="Left" Height="23" Margin="216,76,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" RenderTransformOrigin="0.679,0.552"/>
<TextBox x:Name="TextBox3" HorizontalAlignment="Left" Height="23" Margin="216,121,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" RenderTransformOrigin="0.679,0.552"/>
<TextBlock HorizontalAlignment="Left" Margin="68,30,0,0" TextWrapping="Wrap" Text="First Number" VerticalAlignment="Top" RenderTransformOrigin="1.137,1.259" Height="16" Width="80"/>
<TextBlock HorizontalAlignment="Left" Margin="68,128,0,0" TextWrapping="Wrap" VerticalAlignment="Top" RenderTransformOrigin="1.137,1.259" Height="16" Width="80" Text="Result"/>
<TextBlock HorizontalAlignment="Left" Margin="68,83,0,0" TextWrapping="Wrap" VerticalAlignment="Top" RenderTransformOrigin="1.137,1.259" Height="16" Width="99" Text="Second Number"/>
<Button Content="+" HorizontalAlignment="Left" Margin="73,172,0,0" VerticalAlignment="Top" Width="75" Click="Add"/>
<Button Content="-" HorizontalAlignment="Left" Margin="179,172,0,0" VerticalAlignment="Top" Width="75" Click="Sub"/>
<Button Content="*" HorizontalAlignment="Left" Margin="286,172,0,0" VerticalAlignment="Top" Width="75" Click="Multi"/>
<Button Content="/" HorizontalAlignment="Left" Margin="392,172,0,0" VerticalAlignment="Top" Width="75" Click="Div"/>
</Grid>
My MainWindowdow.Xaml.cs code is..
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace CalculatorNew
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Add(object sender, RoutedEventArgs e)
{
TextBox3.Text = (System.Convert.ToDecimal(TextBox1.Text) + System.Convert.ToDecimal(TextBox2.Text)).ToString();
}
private void Sub(object sender, RoutedEventArgs e)
{
TextBox3.Text = (System.Convert.ToDecimal(TextBox1.Text) - System.Convert.ToDecimal(TextBox2.Text)).ToString();
}
private void Div(object sender, RoutedEventArgs e)
{
TextBox3.Text = (System.Convert.ToDecimal(TextBox1.Text) / System.Convert.ToDecimal(TextBox2.Text)).ToString();
}
private void Multi(object sender, RoutedEventArgs e)
{
TextBox3.Text = (System.Convert.ToDecimal(TextBox1.Text) * System.Convert.ToDecimal(TextBox2.Text)).ToString();
}
}
}
I am new to WPF and MVVM . So I am finding it a bit difficult to write it in the MVVM format .
Can someone tell me how to rewrite it in MVVM format so that I can use it as a reference for the future?
I think your question has a high chance of being closed because it doesn't demonstrate a minimum willingness to make an effort on your part. Please read a tutorial, there are plenty on the web, and try to understand the concepts first. You need at the very least to understand what a ViewModel is, and how the View relates to it (bindings).
You will probably not get working code that does exactly what you want on this site, I for one am much more interested in explaining how things work.
Anyway, in order to get what you want you need a class that acts as the ViewModel with properties that represent the concepts that you work with. You could have decimal properties that represent the operands and something that represents the operator, and commands that represent each button in the UI. Then you need bindings that link UI elements (textboxes, buttons) to the properties in the ViewModel, and you need to set an instance of the ViewModel as the DataContext of the container for the UI elements you're interested in (be it a Window, Grid or whatever). I think that pretty much sums it up...
You can use this example as a reference. https://code.google.com/p/wpf-mvvm-calculator/downloads/list

Access control within datatemplate

This is XAML:
<Window.Resources>
<DataTemplate x:Key="Temp">
<DockPanel Width="Auto" Background="White" LastChildFill="False">
<TextBox Name="txtBox" TextWrapping="Wrap" DockPanel.Dock="Left" Text="{Binding RelativeSource={RelativeSource AncestorType=ContentControl}, Path=Content}" Height="20" Width="100"/>
<StackPanel Orientation="Vertical">
<RadioButton Content="Option1" HorizontalAlignment="Left" Height="16" Width="112" Click="RadioButton_Click" />
</StackPanel>
</DockPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<ContentControl ContentTemplate="{DynamicResource Temp}" Content="1"/>
</Grid>
This is codebehind:
private void RadioButton_Click(object sender, RoutedEventArgs e)
{
StackPanel sp = ((RadioButton)sender).Parent as StackPanel;
DockPanel dp = sp.Parent as DockPanel;
TextBox txtbox = dp.FindName("txtBox") as TextBox;
MessageBox.Show(txtbox.Text);
}
Is there a more simple way to access the textbox?
(As I know I can't get Parent of parent e.g. Parent.Parent...)
Your code is not that complex!
However, you could simplify it by using Linq-to-VisualTree:
private void RadioButton_Click(object sender, RoutedEventArgs e)
{
RadioButton rb = sender as RadioButton;
TextBox txtbox= rb.Ancestors<DockPanel>().First().Elements<TextBox>().First() as TextBox;
MessageBox.Show(txtbox.Text);
}
The Linq query above finds the first DockPanel ancestor of your RadioButton (i.e. the Parent.Parent that you wanted!), then finds the first TextBox child of the DockPanel.
However, I typically use Linq-to-VisualTree in cases where the query is more complex. I thin your approach is OK really!
Among other things you can add a reference to it in the RadioButton.Tag:
<RadioButton Content="Option1" HorizontalAlignment="Left" Height="16" Width="112"
Click="RadioButton_Click" Tag="{x:Reference txtBox}" />
private void RadioButton_Click(object sender, RoutedEventArgs e)
{
var textBox = (sender as FrameworkElement).Tag as TextBox;
//...
}

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