I have 3 textbox. How can i know which one of them has the focus?
if (TextBoxExtendedSearchName.Focus() == false &&
TextBoxExtendedSearchNomenclature.Focus() == false
&& TextBoxExtendedSearchSpecialist.Focus() == false)
{
window.Close();
}
this does not work
I Use WPF
private void TextBox1_LostFocus(object sender, RoutedEventArgs e)
{
if (!TextBox1.IsFocused && !TextBox2.IsFocused)
MessageBox.Show("Not Focus");
}
private void TextBox2_LostFocus(object sender, RoutedEventArgs e)
{
if (!TextBox1.IsFocused && !TextBox2.IsFocused)
MessageBox.Show("Not Focus");
}
this example not work
I think I understand what the problem is. it does not work when I'm doing it in the event Lost Focus.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void TextBox1_LostFocus(object sender, RoutedEventArgs e)
{
if (!TextBox1.IsFocused && !TextBox2.IsFocused)
MessageBox.Show("Not Focus");
else
MessageBox.Show("Yes Focus");
}
private void TextBox2_LostFocus(object sender, RoutedEventArgs e)
{
if (!TextBox1.IsFocused && !TextBox2.IsFocused)
MessageBox.Show("Not Focus");
else
MessageBox.Show("Yes Focus");
}
XAml
<Window x:Class="TrainWPF.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>
<TextBox x:Name="TextBox1" HorizontalAlignment="Left" Height="25" Margin="62,61,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="205" LostFocus="TextBox1_LostFocus"/>
<TextBox x:Name="TextBox2" HorizontalAlignment="Left" Height="23" Margin="62,145,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="205" LostFocus="TextBox2_LostFocus"/>
<Button Content="Button" HorizontalAlignment="Left" Margin="267,249,0,0" VerticalAlignment="Top" Width="96" RenderTransformOrigin="0.5,0.5" Height="37">
<Button.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="0.397"/>
<TranslateTransform/>
</TransformGroup>
</Button.RenderTransform>
</Button>
</Grid>
</Window>
this does not work
I understand it's my logical error
try this:
//Logical focus
var focusedControl = FocusManager.GetFocusedElement(this);
//KeyBoard focus
var focusedControl = Keyboard.FocusedElement;
// dummy logic to close the window when all the three textboxes are not focused.
List<TextBox> items=new List<TextBox>();
items.Add(TextBoxExtendedSearchName);
items.Add(TextBoxExtendedSearchNomenclature);
items.Add(TextBoxExtendedSearchSpecialist);
if(!items.Any(o=>o==focusedControl))
{
window.Close();
}
You are using the wrong function. You need to use the IsFocused property to get it a Control has a focus.
See the documentation here: Link
With your code:
if (!TextBoxExtendedSearchName.IsFocused
&& !TextBoxExtendedSearchNomenclature.IsFocused
&& !TextBoxExtendedSearchSpecialist.IsFocused)
{
window.Close();
}
This will Close the window if none of them has a Focus.
Related
I'm working with WPF Popup. A popup contains some keyboard.
I want to open a popup when a user clicks on a text box and do not hide a popup while textbox has the focus.
Also I need to hide a popup when a user clicks somewhere away from a popup.
Here's the xaml code:
<Grid>
<StackPanel>
<TextBox x:Name="textBox" GotKeyboardFocus="textBox_GotFocus" MouseDown="textBox_MouseDown" />
<Popup x:Name="popup" Width="100" Height="100" PlacementTarget="{Binding ElementName=textBox}" Placement="Bottom"
StaysOpen="{Binding ElementName=text,Path=IsKeyboardFocused}">
<Grid Background="Blue">
</Grid>
</Popup>
</StackPanel>
</Grid>
Here's the c# code:
private void textBox_GotFocus(object sender, KeyboardFocusChangedEventArgs e)
{
popup.IsOpen = true;
}
private void textBox_MouseDown(object sender, MouseButtonEventArgs e)
{
popup.IsOpen = true;
}
I found that the binding can help:
StaysOpen="{Binding ElementName=,Path=IsKeyboardFocused}"
But the TextBox never hides. Also if I set StaysOpen="False" the TextBox never shows
You could handle the LostKeyboardFocus event and check whether the new focused element is the TextBox itself or if it's a child element of the Popup:
private void textBox_GotFocus(object sender, KeyboardFocusChangedEventArgs e)
{
popup.IsOpen = true;
}
private void textBox_LostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
var newFocusedElement = e.NewFocus as DependencyObject;
//if the focused element is a child of the window, it can't be the child of the popup
if (newFocusedElement == null || FindParent<Window>(newFocusedElement) != null)
popup.IsOpen = false;
}
private void popup_LostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
popup.IsOpen = e.NewFocus == textBox;
}
private static T FindParent<T>(DependencyObject dependencyObject) where T : DependencyObject
{
var parent = VisualTreeHelper.GetParent(dependencyObject);
if (parent == null) return null;
var parentT = parent as T;
return parentT ?? FindParent<T>(parent);
}
Sample XAML:
<StackPanel>
<TextBox x:Name="textBox" GotKeyboardFocus="textBox_GotFocus" LostKeyboardFocus="textBox_LostKeyboardFocus" />
<Popup x:Name="popup" Width="100" Height="100" PlacementTarget="{Binding ElementName=textBox}"
LostKeyboardFocus="popup_LostKeyboardFocus"
Placement="Bottom">
<Grid x:Name="popupRoot" Background="Blue">
<TextBox Margin="10" />
</Grid>
</Popup>
<TextBox />
</StackPanel>
I have a WPF application that has an animated .gif used to briefly direct user attention. The .gif sits just outside of the bounds of my app's window, such that it is underneath, and covered by, the title bar.
See below:
Is there a way to force it to overlay on top? It's defined in XAML like this:
<Grid>
<Image Margin="-5 -45 0 0" DockPanel.Dock="Left" gif:ImageBehavior.AnimatedSource="/Resources/jump.gif"
Width="30" RenderTransformOrigin="0.5,0.5">
<Image.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="45"/>
<TranslateTransform/>
</TransformGroup>
</Image.RenderTransform>
</Image>
</Grid>
And it looks alright at design-time:
I tried using DockPanel instead of Grid as its container to no avail.
Lastly, is it possible to have it behave as though it was collapsed? That is, have it not take up horizontal space between the ComboBox and the Legend Label
You need to use a Popup so that it gets its own window handle. This will also make it not take up space in the layout. As an added bonus (or maybe headache) you will be able to position it with its PlacementTarget and PlacementMode properties, since it looks like that is what you are trying to do anyway.
I used a Popup and it is working quite well, but with some very little flickering.
<Window x:Name="Window1" .../>
<Grid>
<Button Content="Show" HorizontalAlignment="Left" Margin="160,114,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click_1"/>
<Button Content="Hide" HorizontalAlignment="Left" Margin="265,114,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click_2"/>
<Popup x:Name="Popup1" UseLayoutRounding="True" IsOpen="False" Placement="Top" PlacementTarget="{Binding ElementName=Window1}">
<Image Source="C:\\Users\\Public\\Pictures\\Sample Pictures\\desert.jpg" Stretch="Fill" Width="75" Height="25"/>
</Popup>
</Grid>
</Window>
Code :
private void Button_Click_1(object sender, RoutedEventArgs e)
{
Popup1.IsOpen = true;
}
private void Button_Click_2(object sender, RoutedEventArgs e)
{
Popup1.IsOpen = false;
}
private void Window1_LocationChanged(object sender, EventArgs e)
{
double offset = Popup1.HorizontalOffset;
Popup1.HorizontalOffset = offset + 1;
Popup1.HorizontalOffset = offset;
}
Another approach (recommended) without Popup !
XAML
MainWindow.xaml
<Window x:Class="WpfWindow.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="Window1" Title="MainWindow" Height="350" Width="525"
Closing="Window1_Closing" Activated="Window1_Activated" LocationChanged="Window1_LocationChanged">
<Grid x:Name="root"/>
</Window>
TitleBarWindow.xaml
<Window x:Class="WpfWindow.TitleBarWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Topmost="True"
Title="TitleBarWindow" AllowsTransparency="True" WindowStyle="None" Height="25" Width="200">
<Grid>
<Image Source="g:\\jellyfish.jpg" Stretch="Fill" HorizontalAlignment="Stretch"/>
</Grid>
</Window>
MainWindow.xaml.cs
namespace WpfWindow
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
TitleBarWindow w = new TitleBarWindow();
public MainWindow()
{
InitializeComponent();
w.ShowActivated = true;
w.Background = Brushes.Red;
}
private void Window1_LocationChanged(object sender, EventArgs e)
{
Point pt = Window1.PointToScreen(new Point(0, 0));
w.Top = pt.Y - 27;
w.Left = pt.X;
}
private void Window1_Activated(object sender, EventArgs e)
{
Point pt = Window1.PointToScreen(new Point(0, 0));
w.Top = pt.Y-27;
w.Left = pt.X;
w.Show();
}
private void Window1_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
w.Close();
}
}
}
Second approach is very good, works smoothly.
How can change runtime position of a canvas in which dynamically I added controls like (labels, lines)?
I can zoom canvas with all controls but I can't move in another position with MouseMove, MouseUp, MouseDown.
<Canvas Name="canvas" Width="1000" Height="400"
Margin="100 0 0 50"
Background="White"
VerticalAlignment="Bottom"
HorizontalAlignment="Center"
MouseWheel="Canvas_MouseWheel"
MouseMove="Canvas_MouseMove"
MouseUp="Canvas_MouseUp"
MouseDown="Canvas_MouseDown">
<Canvas.RenderTransform>
<ScaleTransform x:Name="st" />
</Canvas.RenderTransform>
</Canvas>
I find this code in internet but for my case is not working
bool activated;
Point point;
private void Canvas_MouseDown(object sender, MouseButtonEventArgs e)
{
activated = true;
point = Mouse.GetPosition(canvas);
Mouse.Capture(canvas);
}
private void Canvas_MouseMove(object sender, MouseEventArgs e)
{
if (activated)
{
double top = Canvas.GetTop(canGraph) + Mouse.GetPosition(canvas).Y - point.Y;
Canvas.SetTop(canvas, top);
double left = Canvas.GetLeft(canvas) + Mouse.GetPosition(canvas).X - point.X;
Canvas.SetLeft(canvas, left);
point = Mouse.GetPosition(canvas);
}
}
private void Canvas_MouseUp(object sender, MouseButtonEventArgs e)
{
activated = false;
Mouse.Capture(null);
}
Edit - The previous solution that I provided was not going to work after the first move of the element without more code so here's a better one
In order to be working correctly the canvas element have to be aligned to the coordinate system of it's parent, which we achieve as we put the canvas in top left corner, if you don't put it there you have to calculate the difference yourselve.
Code behind
private void Canvas_MouseDown(object sender, MouseButtonEventArgs e)
{
canvas.CaptureMouse();
}
Stopwatch sw = new Stopwatch();
private void Canvas_MouseMove(object sender, MouseEventArgs e)
{
if (canvas.IsMouseCaptured)
{
translate.X = e.GetPosition(container).X;
translate.Y = e.GetPosition(container).Y;
}
}
private void Canvas_MouseUp(object sender, MouseButtonEventArgs e)
{
canvas.ReleaseMouseCapture();
}
XAML
<Grid Background="Green" x:Name="container">
<Canvas Name="canvas" Width="100" Height="100"
Margin="0 0 0 0"
Background="Purple"
VerticalAlignment="Top"
HorizontalAlignment="Left"
MouseMove="Canvas_MouseMove"
MouseDown="Canvas_MouseDown">
<StackPanel Background="White">
<TextBlock >asdasda</TextBlock>
<TextBlock >cccc</TextBlock>
<TextBlock >aaaaa</TextBlock>
<TextBlock >bbbb</TextBlock>
</StackPanel>
<Canvas.RenderTransform>
<TransformGroup>
<ScaleTransform x:Name="st" />
<TranslateTransform x:Name="translate" />
</TransformGroup>
</Canvas.RenderTransform>
</Canvas>
</Grid>
Original answer
XAML
I'd do something like this:
Add a translate transform and to keep you previous transform put it in a group
Use translate transform in order to move the canvas with positions from the mouse events
For starting point of your translations you can use coordinates in the container
Code behind:
bool activated;
Point point;
private void Canvas_MouseDown(object sender, MouseButtonEventArgs e)
{
activated = true;
point = e.GetPosition(container);
}
private void Canvas_MouseMove(object sender, MouseEventArgs e)
{
if (activated)
{
translate.X = e.GetPosition(container).X - point.X;
translate.Y = e.GetPosition(container).Y - point.Y;
}
}
private void Canvas_MouseUp(object sender, MouseButtonEventArgs e)
{
activated = false;
}
XAML
<Canvas Name="canvas" Width="100" Height="100"
Margin="0 0 0 0"
Background="Purple"
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"
MouseMove="Canvas_MouseMove"
MouseUp="Canvas_MouseUp"
MouseDown="Canvas_MouseDown">
<Canvas.RenderTransform>
<TransformGroup>
<ScaleTransform x:Name="st" />
<TranslateTransform x:Name="translate" />
</TransformGroup>
</Canvas.RenderTransform>
</Canvas>
</Grid>
After mouse down then again I move the canvas is start to move from first position when is been.
P.s.
I add this for more stable code , but always return back to the first position
private void Canvas_MouseLeave(object sender, MouseEventArgs e)
{
activated = false;
}
I want to make this as, once i select the first item(Student Information) of the first_ComboBox want to appear second_ComboBox.
How can I make this happen
In the cs code
private void first_ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
}
private void second_ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
}
in XAML
<StackPanel Margin="97,47,171,499" Orientation="Horizontal" Grid.Row="1">
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="Where You want to Control" VerticalAlignment="Top" Height="82" Width="463" FontSize="36"/>
<ComboBox x:Name="first_ComboBox" HorizontalAlignment="Left" VerticalAlignment="Top" Width="560" Height="42" SelectionChanged="first_ComboBox_SelectionChanged">
<x:String>Student Information</x:String>
<x:String>Staff Information</x:String>
<x:String>Academic Information</x:String>
</ComboBox>
</StackPanel>
<StackPanel Margin="97,172,171,374" Orientation="Horizontal" Grid.Row="1">
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="Select the Field" VerticalAlignment="Top" Height="82" Width="463" FontSize="36"/>
<ComboBox x:Name="second_ComboBox" HorizontalAlignment="Left" VerticalAlignment="Top" Width="560" Height="42" SelectionChanged="second_ComboBox_SelectionChanged">
<x:String>Student Name</x:String>
<x:String>Student Address</x:String>
</ComboBox>
</StackPanel>
On your Form main, you can set the visibility of Second Combobox to be false, and then on the first combobox selection changed set it to true, Something like this
public MainWindow()
{
InitializeComponent();
second_ComboBox.Visibility = Visibility.Collapsed;
}
private void first_ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var selecteditem = first_ComboBox.SelectedItem as string;
if (selecteditem != null)
{
second_ComboBox.Visibility = Visibility.Visible;
}
}
on initialization make second combobox visiblity hidden
public MainWindow()
{
InitializeComponent();
second_ComboBox.Visibility = Visibility.Collapsed;
}
private void first_ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
first_ComboBox.Visibility = System.Windows.Visibility.Visible;
}
This question already has answers here:
What is an IndexOutOfRangeException / ArgumentOutOfRangeException and how do I fix it?
(5 answers)
Closed 1 year ago.
I am working on WPF TreeViews. I am able to add the new Items under tree, but I am not able to delete them from the list. In my code I am trying to get the index of the selected tree item and trying to Remove it. But the code is returning Index "-1". This results in an ArgumentOutOfRangeException.
Please help to fix this.
<Window x:Class="MyTreeStructure.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>
<Button Content="ADD" Height="23" HorizontalAlignment="Left" Margin="211,50,0,0"
Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" />
<TreeView Height="200" HorizontalAlignment="Left" Margin="27,12,0,0" Name="treeView1"
VerticalAlignment="Top" Width="120" >
<TreeViewItem Name="Parent" Header="My Tree Content">
</TreeViewItem>
</TreeView>
<TextBox Height="23" HorizontalAlignment="Left" Margin="211,12,0,0" Name="textBox1"
VerticalAlignment="Top" Width="120" />
<Button Content="Delete" Height="23" HorizontalAlignment="Left" Margin="211,79,0,0"
Name="button2" VerticalAlignment="Top" Width="75" Click="button2_Click" />
</Grid>
</Window>
namespace MyTreeStructure
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
TreeViewItem temp = new TreeViewItem();
temp.Header = textBox1.Text;
Parent.Items.Add(temp);
}
private void button2_Click(object sender, RoutedEventArgs e)
{
textBox1.Text = treeView1.SelectedItem.ToString();
Parent.Items.RemoveAt(treeView1.Items.IndexOf(treeView1.SelectedItem));
**// Here I am getting exception. What should be the code here ??**
}
}
}
below line is having the problem
treeView1.Items.IndexOf(treeView1.SelectedItem))
Since treeview1 is only having one node 'Parent' , rest of the node which you have added is in the node called 'Parent'.
So if you trying to get the index for a node in treeView1.Items it will return -1 except for the node called 'Parent' for which it will return 0.
so you nned to modify the code for removing a node as below.
private void button2_Click(object sender, RoutedEventArgs e)
{
textBox1.Text = treeView1.SelectedItem.ToString();
int index = treeView1.Items.IndexOf(treeView1.SelectedItem));
if(index < 0)
{
index = Parent.Items.IndexOf(treeView1.SelectedItem));
}
if(index > 0)
{
Parent.Items.RemoveAt(index);
}
}
I am not familiar with WPF but in WinForms your approach will cause errors. The first one could be a result of the internal numeration of items. It is like this:
0
-0
-1
-2
1
-0
-0
-1
-1 ...
Another stumbling stone is that IndexOf returns -1 (as you mentioned) if the item was not found. You have to check if the value is -1 first, then navigate to the correct Sublist in Treeview.Nodes.Nodes... and finally call RemoveAt().
I Hope this was helpful
Patrick
Here's my two cents worth. This code is working on my machine.
TreeViewItem t;
private void button2_Click(object sender, RoutedEventArgs e)
{
// Delete the node
Parent.Items.RemoveAt(Parent.Items.IndexOf(t));
}
private void treeView1_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
// Get the selected node
t = (TreeViewItem)(((TreeView)e.Source).SelectedItem);
}
<Grid>
<TextBox Height="23" HorizontalAlignment="Left" Margin="8,14,0,0" Name="textBox1" VerticalAlignment="Top" Width="127" />
<Button Height="23" Margin="140,14,0,0" Name="button1" VerticalAlignment="Top" HorizontalAlignment="Left" Width="76" Click="button1_Click">Add Item</Button>
<Button Height="23" Margin="226,14,124,0" Name="DeleteButton" VerticalAlignment="Top" Click="DeleteButton_Click">Delete Item</Button>
<TreeView Margin="10,100,0,13" Name="TreeView1" HorizontalAlignment="Left" VerticalAlignment="Top" Width="194" Height="200">
<TreeViewItem x:Name="Parent" Header="Cold Drinks">
<TreeViewItem Header="Coke"></TreeViewItem>
<TreeViewItem Header="Pepsi"></TreeViewItem>
<TreeViewItem Header="Orange Juice"></TreeViewItem>
<TreeViewItem Header="Milk"></TreeViewItem>
<TreeViewItem Header="Iced Tea"></TreeViewItem>
<TreeViewItem Header="Mango Shake"></TreeViewItem>
</TreeViewItem>
</TreeView>
</Grid>
private void button1_Click(object sender, RoutedEventArgs e)
{
TreeViewItem newChild = new TreeViewItem();
newChild.Header = textBox1.Text;
Parent.Items.Add(newChild);
}
private void DeleteButton_Click(object sender, RoutedEventArgs e)
{
int index = TreeView1.Items.IndexOf(TreeView1.SelectedItem);
if (index < 0)
{
index = Parent.Items.IndexOf(TreeView1.SelectedItem);
}
if (index >= 0 && ((System.Windows.Controls.TreeViewItem)TreeView1.SelectedItem).Name.Contains("Parent"))
{
TreeView1.Items.RemoveAt(index);
}
else if (index >= 0)
{
Parent.Items.RemoveAt(index);
}
}