Keydown event within WPF - wpf

I currently have a basic click button in WPF which the user can press in order to search I want to add a keydown event. When using standard VB I can
simply implement an e.keycode, but because I'm using WPF it seems to be different. I have included my basic click function below, could someone add to it just so it accepts the enter key as well?
Private Sub BTNSearch_Click(sender As Object, e As EventArgs) Handles BTNSearch.Click
Dim latitude As Double = Double.Parse(TXTLat.Text.Substring(0, TXTLat.Text.IndexOf(","c)))
Dim longitude As Double = Double.Parse(TXTLong.Text.Substring(TXTLong.Text.IndexOf(","c) + 1))
Dim location = New Microsoft.Maps.MapControl.WPF.Location(latitude, longitude)
Dim Pin = New Microsoft.Maps.MapControl.WPF.Pushpin()
BingMap.Children.Add(Pin)
Pin.Location = location
BingMap.Center = location
BingMap.ZoomLevel = "18"
End Sub

Buttons are not really designed to handle keyboard input. If you want a key event to trigger the button you should consider using InputBindings to trigger an ICommand that both a KeyBinding and the button are bound to, like this:
<Window>
<Window.InputBindings>
<KeyBinding Key="F5"
Command="{Binding MessageCommand}" />
</Window.InputBindings>
<Button Command="{Binding MessageCommand}">Click Me</Button>
</Window>
The Window would have its DataContext set to a ViewModel with a MessageCommand property of an ICommand that implements the behavior of the button.
A very good tutorial on input binding can be found here.

Related

How to get name of element with focus in WPF

I'm building a Mahjong game that has more buttons than Sgt. Pepper's band. The movement of the tile is simulated by showing the background of the button (tile) in question. I'd like to leverage the use of x:Name="button"and have only one click event, than 200 but the problem is in getting the name of the focused button. I can get the element with the focus but can not access the name property, if I could I would save a lot of inelegant drudgery. Here's what I'd like to do;
Private Sub b15_Click(sender As Object, e As RoutedEventArgs) Handles b15.Click
Dim brush As Brush
Dim vButton As Button
Dim InputElement As IInputElement = Keyboard.FocusedElement
vButton.Name = InputElement.name '!! here's the problem !!
If vTog = 0 Then 'background brush transferred from
brush = vButton.Background
vButton.Background = Nothing
vTog = 1
Else 'background brush transferred to
vButton.Background = brush
vTog = 0
End If
End Sub
Maybe I've missed an easy way to get the button's name so I can use it directly in the code behind. Thank you.
I recommend learning more about the basics of WPF.
As well as "regular" events WPF has routed events. See the signature of your click handler? Notice Routedeventargs rather than eventargs?
That click event is a routed event.
Routed events bubble ( up the visual tree ) and or tunnel (down the visual tree).
https://learn.microsoft.com/en-us/dotnet/framework/wpf/advanced/routed-events-overview
Because of this mechanism, you can handle a click event of buttons at a container further up the visual tree. That could be a grid, stackpanel or window.
In the handler, cast the originalsource of the event to button and that will have a name property.
I do c# but there is very little code to this and if you have trouble following it then you could put it through an online code converter.
Markup:
Title="MainWindow"
ButtonBase.Click="Window_Button_Click"
>
<StackPanel>
<Button Name="b1" Content="b1"/>
<Button Name="b2" Content="b2"/>
<Button Name="b3" Content="b3"/>
</StackPanel>
</Window>
Handler in code behind:
private void Window_Button_Click(object sender, RoutedEventArgs e)
{
Button btn = e.OriginalSource as Button;
if(btn!=null)
{
Debug.WriteLine(btn.Name ?? "No Name for this button");
}
}
If I spin that up with an f5, I see the name of each button clicked output to my output window when I click on them.
As an aside.
I'm not clear what the player clicks and what that does.
Maybe this could work in a generic way and the datacontext of each button would be a viewmodel holding x,y location or some such.

How to wait for the event inside a function?

I'm trying to write a function in VB.Net WPF application for retrieving document’s height in MS WebBrowser control. I can get this value only after some time, when page has been rendered. So, I tried:
Private Function GetHeight(ByVal htmlstring As String) As Integer
Dim wb As New WebBrowser 'Declare WebBrowser
wb.Width = 940 'set Width
wb.NavigateToString(htmlstring) 'Navigate to content
Do Until wb.IsLoaded 'Wait until page is rendered
Loop
'Get DOM Document
Dim doc As mshtml.HTMLDocument = wb.Document
'Get sought value
Dim RetVal As Integer = CInt(doc.body.getAttribute("scrollHeight").ToString)
doc = Nothing : wb.Dispose() : wb = Nothing 'Free variables
Return RetVal 'Return value
End Function
But calling such function causes application to freeze. What should I do? Do I need to implement Async and Await keywords, as well as Threading.Tasks and how to achieve this?
According to MSDN, IsLoaded is a framework element property that indicates whether or not the control has been loaded for presentation, not whether the WebBrowser control's web page has been loaded.
While I question why you would instantiate a browser and have it navigate to a page in a method called "GetHeight"... what I think you want to do here is subscribe to the LoadCompleted event: https://msdn.microsoft.com/en-us/library/system.windows.controls.webbrowser.loadcompleted(v=vs.110).aspx
Perhaps you can construct your webbrowser and have it navigate in a different method, and subscribe to the LoadCompleted event with your GetHeight method?
Edit I neglected to mention that because you declared your browser control outside of xaml, the control will never be loaded (and thus, navgiation won't work) because it's not in the visual tree of the WPF application. You'll have to either use a webbrowser already declared in xaml (which I would recommend), or add it programmatically with something like this:
<Window x:Class="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 x:Name="MainPanel">
<Button Click="Button_Click"> Clicky</Button>
</StackPanel>
Class MainWindow
Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
Dim wb As New WebBrowser 'Declare WebBrowser
wb.Width = 940 'set Width
Me.MainPanel.Children.Add(wb)
wb.NavigateToString("www.stackoverflow.com")
AddHandler wb.LoadCompleted, Sub(s, ee) DoSomething()
End Sub
Private Sub DoSomething()
MessageBox.Show("blah")
End Sub
End Class

How to write out button event without using WPF controls?

I do not know how to specify in the title, this is in WPF visual basic. I want to know how do I write a code so that when a button is clicked, the tabcontrol selection will be = 1
Here is what I have in my MainWindow, RightWindowCommands:
<Button Content="Information" Cursor="Hand" Click="InformationButton_OnClick"
ToolTip="View the information"
x:Name="InformationView"/>
However, I did not use the WPF tools' Button, as this is a GUI that I have to place the button at RightWindowCommands, I want to know how to come out with the code so that InformationButton_OnClick gives me tabControl.SelectedIndex = 1. Please guide me on writing this code out
Here is a nice example for onclick event handling a picture, you can change it to a number instead of picture.
`AddHandler pic.Click, AddressOf pic_Click'
Private Sub pic_Click(ByVal sender As Object, ByVal e As EventArgs)
Dim pic As PictureBox = DirectCast(sender, PictureBox)
' etc...
End Sub
Source : add on click event to picturebox vb.net

TextBox and default Button binding does update too late

I've got a simple WPF dialog with these two controls:
<TextBox Text="{Binding MyText}"/>
<Button Command="{Binding MyCommand}" IsDefault="True"/>
Now, when I enter some text in the TextBox and click the button using the mouse, everything works like expected: the TextBox will set MyText and MyCommand is called.
But when I enter some text and hit enter to "click" the default button, it does not work. Since on hitting enter the focus does not leave the TextBox, the binding will not be refresh MyText. So when MyCommand is called (which works), MyText will contain old data.
How do I fix this in MVVM? In classic code-behind I probably just would call "MyButton.Focus()" in the MyCommand handler, but in MVVM the MyCommand handler does know nothing about the button.
So what now`?
Add the UpdateSourceTrigger to your TextBox with the value PropertyChanged. The default behavior of the Textbox is to update the source, when it´s lost focus.
<TextBox Text="{Binding MyText, UpdateSourceTrigger=PropertyChanged}"/>
Try this. This code moves focus on the button clicked. Thus binding completes before command processed.
public App()
{
EventManager.RegisterClassHandler(typeof(Button), Button.ClickEvent, new RoutedEventHandler(GenericButtonClickHandler));
}
void GenericButtonClickHandler(object sender, RoutedEventArgs e)
{
var button = sender as Button;
if (button == null)
return;
if (button.IsDefault)
button.Focus();
}
One Solution ist, to create your own Class OKButton that calls Me.Focus in the OnClick-Method. This will be called before the Click_Event and before any Command that is bound to the button. You just have to remember to use an OKButton instead of setting IsDefault=True
Public Class OKButton
Inherits System.Windows.Controls.Button
Public Sub New()
MyBase.New()
Me.Content = "OK"
Me.IsDefault = True
End Sub
Protected Overrides Sub OnClick()
Me.Focus()
MyBase.OnClick()
End Sub
End Class

Handling events from user control containing a WPF textbox

In order to take advantage of the spell checking ability of WPF textboxes, I have added one to a user control (with the use of elementhost). This user control is used in various window forms. My current problem is trying to handle keyup events from this textbox but the windows form is unable to "get" any event from the control. I can access the properties of the textbox just fine (i.e. text, length, etc.) but keyboard events don't seem to work.
I have found, however, that the following will bring back events from the WPF textbox:
Public Class MyUserControl
Private _elementHost As New ElementHost
Private _wpfTextbox As New System.Windows.Controls.Textbox
Private Sub MyUserControl_Load(...) Handles Me.Load
Me.Controls.Add(_elementHost)
_elementHost.Dock = DockStyle.Fill
_elementHost.Child = _wpfTextbox
Dim MyEventInfo As EventInfo
Dim MyMethodInfo As MethodInfo
MyMethodInfo = Me.GetType().GetMethod("WPFTextbox_KeyUp")
MyEventInfo = _wpfTextBox.GetType().GetEvent("PreviewKeyUp")
Dim dlg As [Delegate] = [Delegate].CreateDelegate(MyEventInfo.EventHandlerType, Me, MyMethodInfo)
MyEventInfo.AddEventHandler(_wpfTextBox, dlg)
End Sub
Public Sub WPFTextbox_KeyUp(ByVal sender As Object, ByVal e As RoutedEventArgs)
' something goes here
End Sub
End Class
The user control is now able to do something after the PreviewKeyUp event is fired in the WPF textbox. Now, I'm not completely sure how to have the window form containing this user control to work with this.
Im a C# person not VB so please bear with me.. Basically you could assign the event from your Window rather than within your UserControl.. So in the constructor of your Window assign the PreviewKeyUp:
this.myUserContorl.PreviewKeyUp += new System.Windows.Input.KeyEventHandler(WPFTextbox_KeyUp);
then place the event handler in your Window:
private void WPFTextbox_KeyUp(object sender, System.Windows.Input.KeyEventArgs e)
{
}
Incidentally you needn't go through the hassle of capturing the event in your UserControl as you can still access your TextBox within you UserControl directly from your Window (if you make it public), again from your constructor in your Window:
this.myUserContorl.wpfTextbox.PreviewKeyUp += new System.Windows.Input.KeyEventHandler(WPFTextbox_KeyUp);
I imagine it would look like this in VB (at a guess):
AddHandler myUserContorl.wpfTextbox.PreviewKeyUp, AddressOf WPFTextbox_KeyUp
ElementHost has a static method called EnableModelessKeyboardInterop(). Try calling it?
ElementHost.EnableModelessKeyboardInterop();
Read more here
Seems basic, but did you set the KeyPreview to TRUE on your form?

Resources