Touch Bug in WPF? - c#

I made following application (as a test)
XAML:
<Window x:Class="GUITest.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 Background="Transparent">
<TextBlock Text="openDialog" Background="Red" HorizontalAlignment="Center" VerticalAlignment="Top" MouseDown="TextBlock_MouseDown" />
</Grid>
</Window>
C#:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void TextBlock_MouseDown(object sender, MouseButtonEventArgs e)
{
OpenFileDialog dlg = new OpenFileDialog();
Nullable<bool> result = dlg.ShowDialog();
if (result == true)
{
Console.Out.WriteLine(dlg.FileName);
}
}
}
I catch the mouseDown event because it catches both mouse button down events and touch down events. The code has the expected behavior for mouse clicks. Touch gives me some trouble.
If i touch the TextBlock it opens a dialog window as asked. after closing it, any touch on the window opens the dialog window, even if the touch was not on the TextBlock.
Is this a bug? Can i work around this?
EDIT: i posted a workaround, an actual fix would still be usefull

For other people who run into the same problem. This isn't a fix to the problem, but it is a workaround.
I used a button and restyled it to look like a TextBlock
XAML:
<Grid Background="Transparent">
<Button HorizontalAlignment="Left" VerticalAlignment="Top" Click="Button_Click" Content="openDialog">
<Button.Template>
<ControlTemplate TargetType="Button">
<ContentPresenter />
</ControlTemplate>
</Button.Template>
</Button>
</Grid>
Code for Button_Click is the same as TextBlock_MouseDown

Related

How to navigate between windows in WPF? (not browser)

I want to develop a desktop application based on WPF. How do I navigate through C # code from one window to another in a window? in the other word, I have tried to set up a click event for a radiobutton that opens another window in frame or border.
<Window x:Class="WpfNavigation2.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:WpfNavigation2"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded" Closing="Window_Closing">
<Grid>
<Border Margin="10,100,10,10" Background="AliceBlue">
<Grid Name="contergrid">
</Grid>
</Border>
<RadioButton x:Name="radioButton" Content="RadioButton1" HorizontalAlignment="Left" Margin="60,0,0,0" VerticalAlignment="Top" Click="btn1"/>
<RadioButton x:Name="radioButton1" Content="RadioButton2" HorizontalAlignment="Left" Margin="60,37,0,0" VerticalAlignment="Top" Click="btn2"/>
<RadioButton x:Name="radioButton2" Content="RadioButton3" HorizontalAlignment="Left" Margin="60,68,0,0" VerticalAlignment="Top" Click="btn3"/>
</Grid>
</Window>
private void btn1(object sender, RoutedEventArgs e)
{
//open window 1 in border
}
What you are looking for is a ContentPresenter. You can put all kinds of content in a ContentPresenter for example a control
<Border Margin="10,100,10,10" Background="AliceBlue">
<ContentPresenter Name="contentFrame">
</ContentPresenter>
</Border>
private void btn1(object sender, RoutedEventArgs e)
{
Grid grd = new Grid();
grd.Background = new SolidColorBrush(Colors.HotPink);
contentFrame.Content = grd; // replace me with your control / page / window1
}

Making a WPF window click-through, but not its controls

First of all I want to define what I mean by transparent to clicks in the text bellow: It means the clicks go through my window without any processing, directly to whichever window is bellow it. I need this behaviour because this application is meant to be an overlay over a game.
I searched the questions relating to making a window transparent to clicks. I was wondering if there was a way to make the window itself to be transparent to clicks, but not its controls (such as text boxes and buttons).
Here is the markup for the window:
<Window x:Class="QuestBrowser.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Quest Browser"
Height="350" Width="525"
AllowsTransparency="True" WindowStyle="None" Topmost="True">
<Window.Background>
<SolidColorBrush Color="White" Opacity="0.1"/>
</Window.Background>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBox Name="inputTxtBox"></TextBox>
</Grid>
</Window>
And bellow is the code that makes the window transparent to clicks (pretty much copy-pasted from other question, because I'm not good at all at low level Windows programming).
namespace Win32Utils
{
public static class WindowHelper
{
const int WS_EX_TRANSPARENT = 0x00000020;
const int GWL_EXSTYLE = (-20);
public static void SetWindowExTransparent(IntPtr hwnd)
{
var extendedStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
SetWindowLong(hwnd, GWL_EXSTYLE, extendedStyle | WS_EX_TRANSPARENT);
}
}
}
The method WindowHelper.SetWindowExTransparent is called from within my override of the method Window.OnSourceInitialized (as instructed in the post where I got the code for a transparent window from):
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
var hwnd = new WindowInteropHelper(this).Handle;
WindowHelper.SetWindowExTransparent(hwnd);
}
This does make the window transparent to clicks, but all controls I put into it are transparent as well (for example, the TextBox). Is there a way to make the Window surface transparent to clicks, but ensure the TextBox still receives mouse and keyboard input normally?
I wanted to avoid mouse and keyboard hooks for both user privacy reasons and because, as I said, I don't understand much about the Windows API. If hooks are the only way, I would really appreciate a "For Dummies"-style explanation on how they work.
Can you try this
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1"
Height="300"
Width="300"
AllowsTransparency="True"
WindowStyle="None" >
<Window.Background>
<SolidColorBrush Color="#FFB0B0B0"
Opacity="0.05" />
</Window.Background>
<Grid>
<Button Content="Button"
HorizontalAlignment="Left"
Margin="39,125,0,0"
VerticalAlignment="Top"
Width="75" />
<Label Content="Label"
HorizontalAlignment="Left"
Margin="114,50,0,0"
VerticalAlignment="Top" />
<TextBox HorizontalAlignment="Left"
Height="23"
Margin="101,201,0,0"
TextWrapping="Wrap"
Text="TextBox"
VerticalAlignment="Top"
Width="120" />
</Grid>
</Window>
What It basically does Is create a transparent window.(Click through and Invisble). But controls are visible and not-click through.
Or you can try How to create a semi transparent window in WPF that allows mouse events to pass through

Interaction between two usercontrols in WPF without using MVVM

I have two UserControls in my application, both of them reside on the MainWindow. Now I need to interact between these two, so that when I click Button in UserControl1, the Text property of the TextBlock in UserControl2 changes.
How can I achieve this without MVVM? I would love to see the MVVM solution though if it is complete cause I'm totally new to it and it is very overwhelming.
MainWindow:
<Window x:Class="WpfApplication23.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"
xmlns:wpfApplication23="clr-namespace:WpfApplication23">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<wpfApplication23:UserControl1/>
<wpfApplication23:UserControl2 Grid.Row="1"/>
</Grid>
</Window>
UserControl1:
<UserControl x:Class="WpfApplication23.UserControl1"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<Grid>
<Button Content="Change Text"
Width="200"
Height="80"
Click="ButtonBase_OnClick"/>
</Grid>
</UserControl>
UserControl2:
<UserControl x:Class="WpfApplication23.UserControl2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<TextBox Width="100" Height="20"/>
</Grid>
</UserControl>
Click Event for Button:
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
// Access the TextBlock in UserControl2 and Change its Text to "Hello World"
}
To do this without MVVM, you will need to do the following:
Set up an event like "UpdateText" on the first user control, have the button's click method raise this event.
public event Action<string> UpdateText;
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
// Access the TextBlock in UserControl2 and Change its Text to "Hello World"
if (UpdateText != null)
UpdateText("HelloWorld");
}
Listen to the event in MainWindow that then calls a function on the second user control to update the textblock. Something like:
public MainWindow()
{
InitializeComponent();
myUserControl1.UpdateText += HandleUpdateText;
}
private void HandleUpdateText(String newText)
{
myUserControl2.SetText(newText);
}
Now the right answer to do this would be to use MVVM, but the code sample required would be too long for StackOverflow. I will provide the steps however:
Set up a DependencyProperty on the second user control for the "Text" property, and bind to it:
<UserControl x:Class="WpfApplication23.UserControl2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<TextBox Width="100" Height="20" Text="{Binding ControlText}"/>
</Grid>
</UserControl>
Put an ICommand dependency property on the first user control that will be invoked on the button click. Bind a function to it on MainWindow that will set the ControlText property to the parameter object.
Probably not the best "First MVVM" sample, as it requires a few advanced concepts (commanding and dependency properties), but it shouldn't be too hard to implement.

FocusedElement is not being honoured

I have created a basic application using Prism & MVVM. So far, it only consists of the Shell, and one View/ViewModel.
During application load, I am loading the View into my main region and this displays on screen. This works, but I cannot get the textbox on the view to focus. It looks like the cursor is in the box (although it's not flashing), but it doesn't accept text input until I click on the textbox.
I've recreated this in a new project, where all I've done is install prism/prism.unityextensions, set up the shell and the view, and loaded the view into the shell region. Neither xaml file has anything in the code behind.
Shell
<Window x:Class="MVVMFocusTest.Shell"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://www.codeplex.com/prism"
Title="MainWindow" Height="350" Width="525">
<Grid>
<DockPanel LastChildFill="True">
<ContentControl Name="MainRegion" DockPanel.Dock="Top" prism:RegionManager.RegionName="MainRegion" />
</DockPanel>
</Grid>
</Window>
View1
<UserControl x:Class="MVVMFocusTest.View1"
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="300" d:DesignWidth="300">
<StackPanel>
<Grid FocusManager.FocusedElement="{Binding ElementName=Username}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Label Grid.Row="0" Grid.Column="0">Username</Label>
<TextBox Name="Username" Grid.Row="0" Grid.Column="1" ToolTip="Enter Username" TabIndex="0" />
<Label Grid.Row="1" Grid.Column="0">Password</Label>
<PasswordBox Grid.Row="1" Grid.Column="1" Name="LoginPassword" PasswordChar="*" ToolTip="Enter Password" TabIndex="1" />
</Grid>
</StackPanel>
</UserControl>
Can anyone point out what I'm doing wrong? As far as I'm aware, the FocusManager.FocusedElement="{Binding ElementName=Username}" should be sufficient to set the focus.
As per FocusManager documentation -
Logical focus pertains to the FocusManager.FocusedElement within a
specific focus scope.
So, its not necessary that element with logical focus will have keyboard focus as well but vice versa is true i.e. element with keyboard focus will surely have a logical focus as well.
As stated in documentation FocusManager.FocusedElement guarantees logical focus and not keyboard focus. So what you can do is create an attach behaviour similar to FocusManager.FocusedElement which will set keyboard focus on an element.
You can refer to this for setting keyboard focus using attached behaviour - Setting keyboard focus in WPF.
Code from that article -
namespace Invoices.Client.Wpf.Behaviors
{
using System.Windows;
using System.Windows.Input;
public static class KeyboardFocus
{
public static readonly DependencyProperty OnProperty;
public static void SetOn(UIElement element, FrameworkElement value)
{
element.SetValue(OnProperty, value);
}
public static FrameworkElement GetOn(UIElement element)
{
return (FrameworkElement)element.GetValue(OnProperty);
}
static KeyboardFocus()
{
OnProperty = DependencyProperty.RegisterAttached("On", typeof(FrameworkElement), typeof(KeyboardFocus), new PropertyMetadata(OnSetCallback));
}
private static void OnSetCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
var frameworkElement = (FrameworkElement)dependencyObject;
var target = GetOn(frameworkElement);
if (target == null)
return;
frameworkElement.Loaded += (s, e) => Keyboard.Focus(target);
}
}
}
Use in XAML -
<UserControl xmlns:behaviors="clr-namespace:Invoices.Client.Wpf.Behaviors">
<Grid behaviors:KeyboardFocus.On="{Binding ElementName=TextBoxToFocus}">
<TextBox x:Name="TextBoxToFocus" />
</Grid>
</UserControl>
FocusManager.FocusedElement="{Binding ElementName=Username}" sets logical focus but not physical focus.
Physical focus is the normal focus, logical focus is kinda a second focus which is still a little bit buggy in wpf 4.0.
I would suggest you to use Keyboard.Focus(this.Username).

TextBox.Focus() only works if I have a MessageBox.Show() after it?

Ok so obviously there's more to it, but here's the basics. This is seemingly such a simple thing but it's not working.
I have a Label.
I have a TextBox.
The ZIndex of the Label = "1"
The ZIndex of the TextBox = "0"
i.e. They are on top of one another and the TextBox is invisible.
When the user clicks on the LABEL (right now Via PreviewMouseLeftButtonDown but will be a command in ViewModel after this "works") the application should set focus to the TextBox.
Simple right? Wrong...
If I have this code...it does NOT work.
private void inVisTxtBox_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
inVisTxtBox.Focus();
// TextBox_MouseDown(sender, e);
}
If I have this code...it DOES work
private void inVisTxtBox_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
inVisTxtBox.Focus();
// TextBox_MouseDown(sender, e);
MessageBox.Show("This is ridiculous");
}
And finally the XAML:
<Ctrls:AControl x:Class="<location of class>"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:CommandControls="clr-namespace:<location of custom controls>" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<Grid Margin="0,15,15,15">
<!--<Button Height="50" Click="Button_Click">FOC</Button>-->
<TextBox x:Name="inVisTxtBox" Focusable="True" Grid.ZIndex="0" Width="100" Margin="5"/>
<Label Grid.ZIndex="1" Margin="5" Content="243234234234234" HorizontalAlignment="Left" Width="100" PreviewMouseLeftButtonDown="inVisTxtBox_PreviewMouseLeftButtonDown"
x:Name="KeyPress_TextBox"/>
</Grid>
</Ctrls:AControl>
EDIT
If I make the Label into a Templated Button with a label as it's template it works:
<Button x:Name="KeyPress_TextBox" Grid.ZIndex="1" Margin="5" Content="243234234234234" HorizontalAlignment="Left" Width="100" Click="KeyPress_TextBox_Click">
<Button.Template>
<ControlTemplate TargetType="Button">
<Label Content="{TemplateBinding Content}"/>
</ControlTemplate>
</Button.Template>
</Button>
Why is that?
Must have something to do with the way the events route/bubble?
I have it working now by doing that...but I'm more curious what's happening.
Also...none of the following works either:
Keyboard.Focus(inVisTxtBox);
FocusManager.SetFocusedElement(MainGrid,inVisTxtBox);
Keyboard.Focus(inVisTxtBox);
I copied your code and it works fine for me, even with previewmouseclick, something else seems to be the problem.
Likely throwing the message box up stops the focus from shifting to whatever it was going to shift to after the PreviewMouseLeftButtonDown event fires. Perhaps the UserControl itself is getting focus?

Categories

Resources