Windows Phone/Silverlight: check whether a control has input focus - silverlight

How to know whether a control such as TextBox has the input focus in a Windows Phone Silverlight app?

You have to use FocusManager
bool b = FocusManager.GetFocusedElement() == myTextbox;

There are events like GotFocus and LostFocus for controls.
If you subscribe to these events they automatically get called when your input receives or looses focus
you can use those events for your purpose.
XAML Declaration
<TextBox Name="myTextbox" GotFocus="myTextbox_GotFocus" />
and inside the cs
private void myTextbox_GotFocus(object sender, RoutedEventArgs e)
{
}
private void ContentPanel_LostFocus(object sender, RoutedEventArgs e)
{
}

Related

How can I change textbox contents based on which control the mouse is hovering over in WPF?

I have a textbox and several custom controls. Each of the custom controls has a "hint text" property that should appear in the textbox when that control is hovered over.
In winforms I was able to just give the custom control a textbox property and change its text property with events, however in WPF it instead makes a new textbox when I give it a property.
So how can I get the desired functionality?
Assuming your custom controls all inherit from a common base type (which I have called CustomControl as an example)...
XAML:
<TextBox x:Name=TextBox/>
<Button VerticalAlignment="Bottom" Click="ButtonBase_OnClick" MouseEnter="UIElement_OnMouseEnter" MouseLeave="UIElement_OnMouseLeave">test</Button>
Code behind:
private void UIElement_OnMouseEnter(object sender, MouseEventArgs e)
{
TextBox.Text = ((CustomControl) sender).HintText;
}
private void UIElement_OnMouseLeave(object sender, MouseEventArgs e)
{
TextBox.Text = string.Empty;
}

Call a function when the key "space" is pressed in a window

I'm developing a board game and I would like to call a function when space is pressed in the window but I couldn't find answer to my problem during my searches.
Do you have an idea?
Lots of ways to do this. The easiest is to hook up an event handler (albeit not the most elegant). More elegant solutions involving commands can also be used though, depending on what controls you're using.
XAML
<Window KeyDown="MainWindow_OnKeyDown"
<!-- other properties -->
>
<!-- rest of your UI -->
</Window>
Code Behind
private void MainWindow_OnKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Space)
{
// do something
}
}
XAML:
<Window ...
PreviewKeyUp="Window_PreviewKeyUp" >
</Window>
Code behind:
// Use the PreviewKeyUp event to capture the keypress before
// any child controls that have focus handle the event
private void Window_PreviewKeyUp(object sender, KeyEventArgs e)
{
if(e.Key == Key.Space)
{
AFunction();
// to prevent the key press to bubble up to child controls that have focus
e.Handled = true;
}
}

Prevent hyperlink Click event from bubbling up

I'm designing a windows Phone app. I have a Hyperlink object in a RichTextBox, in a Grid. The Grid had a Tap event, and the Hyperlink has a Click event.
Clicking the Hyperlink also raises the parent Grid's Tap event. How can I prevent this?
I would use e.Handled in the Click handler, but RoutedEventArgs do not have a Handled property in Silverlight for Windows Phone... I also tried walking the logical tree to look for the original source, but the click appears to originate from a MS.Internal.RichTextBoxView control (e.OriginalSource)...
I don't think there is any good way from within the Click handler itself. The following state management can work though:
XAML:
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0" Tap="ContentPanel_Tap_1">
<RichTextBox Tap="RichTextBox_Tap_1">
<Paragraph>
fdsfdfdf
<Hyperlink Click="Hyperlink_Click_1">fdsfdsfsaf</Hyperlink>
fsdfsdfa
</Paragraph>
</RichTextBox>
</Grid>
and the code:
bool RtbTapHandled = false;
private void Hyperlink_Click_1(object sender, RoutedEventArgs e)
{
System.Diagnostics.Debug.WriteLine("Hyperlink");
RtbTapHandled = true;
}
private void RichTextBox_Tap_1(object sender, System.Windows.Input.GestureEventArgs e)
{
if (RtbTapHandled)
{
e.Handled = true;
}
RtbTapHandled = false;
System.Diagnostics.Debug.WriteLine("RTB_Tap");
}
private void ContentPanel_Tap_1(object sender, System.Windows.Input.GestureEventArgs e)
{
System.Diagnostics.Debug.WriteLine("Content_Tap");
}
In this case if you click on the RichTextBox you'll get callbacks from both RichTextBox_Tap_1 and ContentPanel_Tap_1, but if you click on the Hyperlink you'll get Hyperlink_Click_1 and RichTextBox_Tap_1 though it'll be handled at that level and stopped.

Silverlight: How to Prevent Routing a MouseMove Event from a Child Canvas to Its Parent Canvas

I have my XAML code:
<Canvas x:Name="mainCanvas" Width="200" Height="150" Background="LightGray"
MouseLeftButtonUp="mainCanvas_MouseLeftButtonUp"
MouseMove="mainCanvas_MouseMove">
<Canvas x:Name="topCanvas" Width="200" Height="100" Background="LightBlue"
MouseLeftButtonUp="topCanvas_MouseLeftButtonUp"
MouseMove="topCanvas_MouseMove">
</Canvas>
</Canvas>
and its code behind:
private void topCanvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
MessageBox.Show("topCanvas_MouseLeftButtonUp");
e.Handled = true; // This can prevent routing to the mainCanvas
}
private void mainCanvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
MessageBox.Show("mainCanvas_MouseLeftButtonUp");
}
private void topCanvas_MouseMove(object sender, MouseEventArgs e)
{
Debug.WriteLine("topCanvas_MouseMove");
// How to prevent routing to the mainCanvas?
// e.Handled = true does NOT exist in MouseEventArgs
}
private void mainCanvas_MouseMove(object sender, MouseEventArgs e)
{
Debug.WriteLine("mainCanvas_MouseMove");
}
My question is already in the comments.
How to prevent routing the MouseMove event from the topCanvas (the child canvas) to the mainCanvas (parent canvas)?
Thanks.
Peter
Try setting the IsHitTestVisible property of your Canvas. With that property set accordingly mouse events will go either "through" your control or will be caught by it.
Hope this is what you need.
You can try comparing e.OriginalSource in mainCanvas's MouseMove Event and exit the Sub if it wasn't originated from the mainCanvas.
private void mainCanvas_MouseMove(object sender, MouseEventArgs e)
{
if (sender != e.OriginalSource)
return;
}
In replying to your comment in a little more detail. According to the UIElement.MouseMove Event MSDN link.
Controls that inherit MouseMove can provide handling for the event
that acts as handler for all instances, by overriding the OnMouseMove
method. As with direct handling of the event, there is no Handled
property available, so OnMouseMove cannot be implemented in such a way
that it suppresses further handling of the event through the Handled
technique.
and this link states:
This event creates an alias for the Mouse.MouseMove attached event for
this class
Which brings us to this link on AttachedEvents which states.
Extensible Application Markup Language (XAML) defines a language
component and type of event called an attached event. The concept of
an attached event enables you to add a handler for a particular event
to an arbitrary element rather than to an element that actually
defines or inherits the event. In this case, neither the object
potentially raising the event nor the destination handling instance
defines or otherwise "owns" the event.
So as I see it, your only option is to code around it.
The functionality is called "Event Bubbling". You can stop it using below code:
jQuery:
event.stopPropagation();
Ref: http://api.jquery.com/event.stopPropagation/
You can also try below code:
e.stopPropagation(); //to prevent event from bubbling up
e.preventDefault(); //then cancel the event (if it's cancelable)
Ref: http://stackoverflow.com/questions/1967537/how-to-stop-event-bubbling-with-jquery-live
Thanks,
Ravi Verma

Is there an MVVM-friendly way to use the WebBrowser control in WPF?

Thanks to this question (click me!), I have the Source property of my WebBrowser binding correctly to my ViewModel.
Now I'd like to achieve two more goals:
Get the IsEnabled property of my Back and Forward buttons to correctly bind to the CanGoBack and CanGoForward properties of the WebBrowser.
Figure out how to call the GoForward() and GoBack() methods without resorting to the code-behind and without the ViewModel having to know about the WebBrowser.
I have the following (non-working) XAML markup at the moment:
<WebBrowser
x:Name="_instructionsWebBrowser"
x:FieldModifier="private"
clwm:WebBrowserUtility.AttachedSource="{Binding InstructionsSource}" />
<Button
Style="{StaticResource Button_Style}"
Grid.Column="2"
IsEnabled="{Binding ElementName=_instructionsWebBrowser, Path=CanGoBack}"
Command="{Binding GoBackCommand}"
Content="< Back" />
<Button
Style="{StaticResource Button_Style}"
Grid.Column="4"
IsEnabled="{Binding ElementName=_instructionsWebBrowser, Path=CanGoForward}"
Command="{Binding GoForwardCommand}"
Content="Forward >" />
I'm pretty sure the problem is that CanGoBack and CanGoForward are not dependency properties (and don't implement INotifyChanged), but I'm not quite sure how to get around that.
Questions:
Is there any way to hook up attached properties (as I did with Source) or something similar to get the CanGoBack and CanGoForward bindings to work?
How do write the GoBackCommand and GoForwardCommand so they are independent of the code-behind and ViewModel and can be declared in markup?
For anyone who comes across this question and wants a complete solution, here it is. It combines all of the suggestions made in this thread and the linked threads (and others those link to).
XAML:
http://pastebin.com/aED9pvW8
C# class:
http://pastebin.com/n6cW9ZBB
Example XAML usage:
http://pastebin.com/JpuNrFq8
Note: The example assumes your view binds to a ViewModel that provides the source URL to the browser. A very rudimentary navigation bar with back, forward, and refresh buttons and address bar is provided just for demonstration.
Enjoy. I have set the expiration on those pastebin's to never, so they should be available for as long as pastebin exists.
I used this in my bindable webbrowser wrapper:
CommandBindings.Add(new CommandBinding(NavigationCommands.BrowseBack, BrowseBack, CanBrowseBack));
CommandBindings.Add(new CommandBinding(NavigationCommands.BrowseForward, BrowseForward, CanBrowseForward));
CommandBindings.Add(new CommandBinding(NavigationCommands.BrowseHome, GoHome, TrueCanExecute));
CommandBindings.Add(new CommandBinding(NavigationCommands.Refresh, Refresh, TrueCanExecute));
CommandBindings.Add(new CommandBinding(NavigationCommands.BrowseStop, Stop, TrueCanExecute));
Note that I created my bindable webbrowser as FrameworkElement that exposes DependencyProperties and calls methods on the actual browser element, so i can set CommandBindings on it.
That way, you can use the default NavigationCommands in your View.
The used handlers are:
private void CanBrowseBack(object sender, CanExecuteRoutedEventArgs e) {
e.CanExecute = webBrowser.CanGoBack;
}
private void BrowseBack(object sender, ExecutedRoutedEventArgs e) {
webBrowser.GoBack();
}
private void CanBrowseForward(object sender, CanExecuteRoutedEventArgs e) {
e.CanExecute = webBrowser.CanGoForward;
}
private void BrowseForward(object sender, ExecutedRoutedEventArgs e) {
webBrowser.GoForward();
}
private void TrueCanExecute(object sender, CanExecuteRoutedEventArgs e) { e.CanExecute = true; }
private void Refresh(object sender, ExecutedRoutedEventArgs e) {
try { webBrowser.Refresh(); }
catch (Exception ex) { PmsLog.LogException(ex, true); }
}
private void Stop(object sender, ExecutedRoutedEventArgs e) {
mshtml.IHTMLDocument2 doc = WebBrowser.Document as mshtml.IHTMLDocument2;
if (doc != null)
doc.execCommand("Stop", true, null);
}
private void GoHome(object sender, ExecutedRoutedEventArgs e) {
Source = new Uri(Home);
}
Your question seems to imply that in order to correctly implement an MVVM pattern you are not allowed to have any code-behind. But perhaps adding some code-behind to your view will make it much easier to hook it up with your view-model. You can add dependency properties to the view and let it listen for INotifyPropertyChanged events.

Resources