Telerik RadTimeline respond to mouse clicks - silverlight

Is there any way to know if the user has clicked on an item in RadTimeline? I would like to handle the click and do something with the selected timeline item, but my searching hasn't revealed any way to handle this. I can capture the mouse click on MouseLeftButtonDown event, but I don't see a way to tell which item was hit, if any.

According to Telerik, this feature is not supported, but will be available for Q1 2012 SP1 or Q2 2012 release.
However, after researching it, I found a workaround that seems to work. If you override the TimelineItemTemplate with a DataTemplate that has a MouseLeftButtonDown event on it, then you can use the DataContext of the sender to get the bound data.
XAML:
<telerik:RadTimeline x:Name="MatchTimeline" Height="250" PeriodStart="3/1/2012" PeriodEnd="3/30/2012">
<telerik:RadTimeline.Intervals>
<telerik:DayInterval/>
<telerik:HourInterval/>
</telerik:RadTimeline.Intervals>
<telerik:RadTimeline.TimelineItemTemplate>
<DataTemplate>
<Border Height="14">
<Grid>
<Rectangle Height="10" Fill="Blue" MouseLeftButtonDown="Rectangle_MouseLeftButtonDown"/>
</Grid>
</Border>
</DataTemplate>
</telerik:RadTimeline.TimelineItemTemplate>
Code:
private void Rectangle_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
MyTimelineItem item = (MyTimelineItem)(((Telerik.Windows.Controls.DataItemBase)(((System.Windows.FrameworkElement)(sender)).DataContext)).DataItem);
item.IWasHere();
}

Related

What do I need to do to get a ListView's selection behavior in WPF to catch up with WinForms?

There are basically two things I am trying to activate or implement:
1. Clearing selection when background is clicked:
Typically, when one clicks in a blank area of a list view type control, such as windows explorer, any selected items become unselected. This is not happening for me in either multiple or extended selection mode. Do I have to manually handle the mouse click event to clear the selection, or is it perhaps not behaving as expected because I've applied a background to the control?
2. Selection rectangle with automatic scrolling:
Before porting my application to WPF, the standard WinForms listview allowed me to drag a selection rectangle and it would select any items it intersected. If there were items scrolled out of view in any direction, dragging in that direction would result in the control automatically scrolling into that area as I dragged the mouse, so I could selected items that are out of view. Does the WPF ListView implement this feature, or am I going to have to implement it myself? Someone posted a non-trivial implementation involving hittests in the comments on this page (http://social.msdn.microsoft.com/Forums/vstudio/en-US/191af722-e32b-4e6d-a00b-9ad2b53ea3b9/listview-dragging-a-selection-box-around-items?forum=wpf), but it doesn't even support the autoscrolling and I'm having a hard time believing Microsoft just left this feature out.
Really ListView has no default appearance and you had to do set even basic selection with trigger.
Wow, this colors and displays the SelectedIndex without a single style or trigger.
All in XAML
<Window.Resources>
<sys:String x:Key="MyString">Hello</sys:String>
<x:Array x:Key="MyStringArray" Type="sys:String">
<sys:String>Hello</sys:String>
<sys:String>World</sys:String>
<sys:String>Continent</sys:String>
<sys:String>Universe</sys:String>
</x:Array>
</Window.Resources>
<Grid>
<StackPanel Orientation="Vertical">
<ListView ItemsSource="{StaticResource MyStringArray}" x:Name="lv" SelectionMode="Single" LostFocus="lv_LostFocus">
</ListView>
<TextBlock Text="{Binding ElementName=lv, Path=SelectedIndex}" />
<Button Content="Take Focus"/>
</StackPanel>
</Grid>
private void lv_LostFocus(object sender, RoutedEventArgs e)
{
lv.SelectedIndex = -1;
}

WebBrowser control keyboard and focus behavior

Apparently, there are some serious keyboard and focus issues with WPF WebBrowser control. I've put together a trivial WPF app, just a WebBrowser and two buttons. The app loads a very basic editable HTML markup (<body contentEditable='true'>some text</body>) and demonstrates the following:
Tabbing is misbehaving. User needs to hit Tab twice to see the caret (text cursor) inside WebBrowser and be able to type.
When user switches away from the app (e.g., with Alt-Tab), then goes back, the caret is gone and she is unable to type at all. A physical mouse click into the WebBrowser's window client area is required to get back the caret and keystrokes.
Inconsistently, a dotted focus rectangle shows up around WebBrowser (when tabbing, but not when clicking). I could not find a way to get rid of it (FocusVisualStyle="{x:Null}" does not help).
Internally, WebBrowser never receives the focus. That's true for both logical focus (FocusManager) and input focus (Keyboard). The Keyboard.GotKeyboardFocusEvent and FocusManager.GotFocusEvent events never get fired for WebBrowser (although they both do for buttons in the same focus scope). Even when the caret is inside WebBrowser, FocusManager.GetFocusedElement(mainWindow) points to a previously focused element (a button) and Keyboard.FocusedElement is null. At the same time, ((IKeyboardInputSink)this.webBrowser).HasFocusWithin() returns true.
I'd say, such behaviour is almost too dysfunctional to be true, but that's how it works. I could probably come up with some hacks to fix it and bring it in row with native WPF controls like TextBox. Still I hope, maybe I'm missing something obscure yet simple here. Has anyone dealt with a similar problem? Any suggestions on how to fix this would be greatly appreciated.
At this point, I'm inclined to develop an in-house WPF wrapper for WebBrowser ActiveX Control, based upon HwndHost. We are also considering other alternatives to WebBrowser, such as Chromium Embedded Framework (CEF).
The VS2012 project can be downloaded from here in case someone wants to play with it.
This is XAML:
<Window x:Class="WpfWebBrowserTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Width="640" Height="480" Background="LightGray">
<StackPanel Margin="20,20,20,20">
<ToggleButton Name="btnLoad" Focusable="True" IsTabStop="True" Content="Load" Click="btnLoad_Click" Width="100"/>
<WebBrowser Name="webBrowser" Focusable="True" KeyboardNavigation.IsTabStop="True" FocusVisualStyle="{x:Null}" Height="300"/>
<Button Name="btnClose" Focusable="True" IsTabStop="True" Content="Close" Click="btnClose_Click" Width="100"/>
</StackPanel>
</Window>
This is C# code, it has a bunch of diagnostic traces to show how focus/keyboard events are routed and where the focus is:
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows;
using System.Windows.Input;
using System.Windows.Navigation;
namespace WpfWebBrowserTest
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
// watch these events for diagnostics
EventManager.RegisterClassHandler(typeof(UIElement), Keyboard.PreviewKeyDownEvent, new KeyEventHandler(MainWindow_PreviewKeyDown));
EventManager.RegisterClassHandler(typeof(UIElement), Keyboard.GotKeyboardFocusEvent, new KeyboardFocusChangedEventHandler(MainWindow_GotKeyboardFocus));
EventManager.RegisterClassHandler(typeof(UIElement), FocusManager.GotFocusEvent, new RoutedEventHandler(MainWindow_GotFocus));
}
private void btnLoad_Click(object sender, RoutedEventArgs e)
{
// load the browser
this.webBrowser.NavigateToString("<body contentEditable='true' onload='focus()'>Line 1<br>Line 3<br>Line 3<br></body>");
this.btnLoad.IsChecked = true;
}
private void btnClose_Click(object sender, RoutedEventArgs e)
{
// close the form
if (MessageBox.Show("Close it?", this.Title, MessageBoxButton.YesNo) == MessageBoxResult.Yes)
this.Close();
}
// Diagnostic events
void MainWindow_GotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
Debug.Print("{0}, source: {1}, {2}", FormatMethodName(), FormatType(e.Source), FormatFocused());
}
void MainWindow_GotFocus(object sender, RoutedEventArgs e)
{
Debug.Print("{0}, source: {1}, {2}", FormatMethodName(), FormatType(e.Source), FormatFocused());
}
void MainWindow_PreviewKeyDown(object sender, KeyEventArgs e)
{
Debug.Print("{0}, key: {1}, source: {2}, {3}", FormatMethodName(), e.Key.ToString(), FormatType(e.Source), FormatFocused());
}
// Debug output formatting helpers
string FormatFocused()
{
// show current focus and keyboard focus
return String.Format("Focus: {0}, Keyboard focus: {1}, webBrowser.HasFocusWithin: {2}",
FormatType(FocusManager.GetFocusedElement(this)),
FormatType(Keyboard.FocusedElement),
((System.Windows.Interop.IKeyboardInputSink)this.webBrowser).HasFocusWithin());
}
string FormatType(object p)
{
string result = p != null ? String.Concat('*', p.GetType().Name, '*') : "null";
if (p == this.webBrowser )
result += "!!";
return result;
}
static string FormatMethodName()
{
return new StackTrace(true).GetFrame(1).GetMethod().Name;
}
}
}
[UPDATE] The situation doesn't get better if I host WinForms WebBrowser (in place of, or side-by-side with WPF WebBrowser):
<StackPanel Margin="20,20,20,20">
<ToggleButton Name="btnLoad" Focusable="True" IsTabStop="True" Content="Load" Click="btnLoad_Click" Width="100"/>
<WebBrowser Name="webBrowser" Focusable="True" KeyboardNavigation.IsTabStop="True" FocusVisualStyle="{x:Null}" Height="150" Margin="10,10,10,10"/>
<WindowsFormsHost Name="wfHost" Focusable="True" Height="150" Margin="10,10,10,10">
<wf:WebBrowser x:Name="wfWebBrowser" />
</WindowsFormsHost>
<Button Name="btnClose" Focusable="True" IsTabStop="True" Content="Close" Click="btnClose_Click" Width="100"/>
</StackPanel>
The only improvement is that I do see focus events on WindowsFormsHost.
[UPDATE] An extreme case: two WebBrowser controls with two carets showing at the same time:
<StackPanel Margin="20,20,20,20">
<ToggleButton Name="btnLoad" Focusable="True" IsTabStop="True" Content="Load" Click="btnLoad_Click" Width="100"/>
<WebBrowser Name="webBrowser" Focusable="True" KeyboardNavigation.IsTabStop="True" FocusVisualStyle="{x:Null}" Height="150" Margin="10,10,10,10"/>
<WebBrowser Name="webBrowser2" Focusable="True" KeyboardNavigation.IsTabStop="True" FocusVisualStyle="{x:Null}" Height="150" Margin="10,10,10,10"/>
<Button Name="btnClose" Focusable="True" IsTabStop="True" Content="Close" Click="btnClose_Click" Width="100"/>
</StackPanel>
this.webBrowser.NavigateToString("<body onload='text.focus()'><textarea id='text' style='width: 100%; height: 100%'>text</textarea></body>");
this.webBrowser2.NavigateToString("<body onload='text.focus()'><textarea id='text' style='width: 100%; height: 100%'>text2</textarea></body>");
This also illustrates that the focus handling issue is not specific to contentEditable=true content.
For anyone else stumbling upon this post and needing to set keyboard focus to the browser control (not a particular element within the control, necessarily), this bit of code worked for me.
First, add a project reference (under Extensions in VS) for Microsoft.mshtml.
Next, whenever you'd like to focus the browser control (say for example, when the Window loads), simply "focus" the HTML document:
// Constructor
public MyWindow()
{
Loaded += (_, __) =>
{
((HTMLDocument) Browser.Document).focus();
};
}
This will place keyboard focus inside the web browser control, and inside the "invisible" ActiveX window, allowing keys like PgUp / PgDown to work on the HTML page.
If you want to, you might be able to use DOM selection to find a particular element on the page, and try to focus() that particular element. I have not tried this myself.
The reason it behaves this way is related to the fact that it's an ActiveX control which itself is a fully windows class (it handles mouse and keyboard interaction). In fact much of the time you see the component used you'll find it is the main component taking up a full window because of this. It doesn't have to be done that way but it presents issues.
Here's a forum discussing the exact same issue and it's causes can be clarified by reading the last commentators article links:
http://social.msdn.microsoft.com/Forums/vstudio/en-US/1b50fec6-6596-4c0a-9191-32cd059f18f7/focus-issues-with-systemwindowscontrolswebbrowser
To outline the issues you're having
Tabbing is misbehaving. User needs to hit Tab twice to see the caret (text cursor) inside WebBrowser and be able to type.
that's because the browser control itself is a window which can be tabbed to. It doesn't "forward" the tab to it's child elements immediately.
One way to change this would be to handle the WM message for the component itself but keep in mind that doing so gets tricky when you want the "child" document inside of it to be able to handle messages.
See: Prevent WebBrowser control from stealing focus? specifically the "answer". Although their answer doesn't account that you can control whether the component interacts through dialogs with the user by setting the Silent property (may or may not exist in the WPF control... not sure)
When user switches away from the app (e.g., with Alt-Tab), then goes back, the caret is gone and she is unable to type at all. A physical mouse click into the WebBrowser's window client area is required to get back the caret and keystrokes.
This is because the control itself has received the focus. Another consideration is to add code to handle the GotFocus event and to then "change" where the focus goes. Tricky part is figuring out if this was "from" the document -> browser control or your app -> browser control. I can think of a few hacky ways to do this (variable reference based on losing focus event checked on gotfocus for example) but nothing that screams elegant.
Inconsistently, a dotted focus rectangle shows up around WebBrowser (when tabbing, but not when clicking). I could not find a way to get rid of it (FocusVisualStyle="{x:Null}" does not help).
I wonder if changing Focusable would help or hinder. Never tried it but I'm going to venture a guess that if it did work it would stop it from being keyboard navigable at all.
Internally, WebBrowser never receives the focus. That's true for both logical focus (FocusManager) and input focus (Keyboard). The Keyboard.GotKeyboardFocusEvent and FocusManager.GotFocusEvent events never get fired for WebBrowser (although they both do for buttons in the same focus scope). Even when the caret is inside WebBrowser, FocusManager.GetFocusedElement(mainWindow) points to a previously focused element (a button) and Keyboard.FocusedElement is null. At the same time, ((IKeyboardInputSink)this.webBrowser).HasFocusWithin() returns true.
People have hit issues with where 2 browser controls both show the focus(well... the caret) or even had a hidden control take the focus.
All in all it's pretty awesome what you can do with the component but it's just the right mix of letting you control/change the behavior along with predefined sets of behavior to be maddening.
My suggestion would be to try to subclass the messages so you can direct the focus control directly through code and bypass it's window from trying to do so.

How could one let the Manipulation or GestureListener work in the page which contains a WebBrowser in it?

My application page contains a WebBrowser. I want to add a GestureListener in order to handle the Flick event. But when Flick on the WebBrowser region, it doesn't work. I have tried many ways to let it work, but I failed. I have also tried to use Manipulation instead, but to no effect.
Could someone tell me how to do or whether there is another solution instead?
Following code is the working solution for the Flick or Hold event on the WebBrowser control.
Try the same, it may help you.
Assuming xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit" being present in the phone:PhoneApplicationPage tag.
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0" Grid.RowSpan="2">
<phone:WebBrowser x:Name="myWebBrowser" Visibility="Visible" IsScriptEnabled="True" IsHitTestVisible="True" Margin="-12,6,0,6" />
<toolkit:GestureService.GestureListener>
<toolkit:GestureListener Flick="GestureListener_Flick" Hold="GestureListener_Hold"></toolkit:GestureListener>
</toolkit:GestureService.GestureListener>
</Grid>
And xaml.cs has functions as follows.
private void GestureListener_Flick(object sender, FlickGestureEventArgs e)
{
MessageBox.Show("Flick");
}
private void GestureListener_Hold(object sender, Microsoft.Phone.Controls.GestureEventArgs e)
{
MessageBox.Show("Hold");
}

Silverlight simulate mouse click by X, Y?

If there is a way to send mouse click event by location programatically it would be great, but if theres another approach that can solve following problem this it is fine too.
In my situation I got a canvas taking up whole application size (covering it completely) and when user clicks it with mouse I want to hide it, and then pass through this mouse click (taking its location x & y from user) to anything that is under canvas (in my case canvas visibility goes to collapsed so controls under it can be seen now).
I am guessing it is impossible, cause certain features like run silverlight fullscreen can only be done in button click handler (correct me if im wrong here).
But is there a place where I can read about those security based limitations of silverlight UI ?
you have to add an click event handler to your canvas. In this handler you get the x and y positon of your click (via MouseButtonEventArgs) and then you can use the VisualTreeHelper to get your "hit elements".
Lets assume the following xaml:
<Grid x:Name="LayoutRoot" Background="White">
<Button Width="50" Height="50" VerticalAlignment="Top" HorizontalAlignment="Left"/>
<TextBox Text="MyText" Width="200" Height="100" VerticalAlignment="Top" HorizontalAlignment="Left"/>
<Canvas Background="Red" x:Name="MyCanvas" />
</Grid>
with the following code behind:
public MainPage()
{
InitializeComponent();
MyCanvas.AddHandler(MouseLeftButtonUpEvent, new MouseButtonEventHandler(handler), true);
}
void handler(object sender, MouseButtonEventArgs e)
{
var point = new Point(e.GetPosition(this).X, e.GetPosition(this).Y);
var elements = VisualTreeHelper.FindElementsInHostCoordinates(point, this);
foreach (var uiElement in elements)
{
if (uiElement is TextBox){
((TextBox) uiElement).Focus();
break;
}
if(uiElement is Button)
{
//do button stuff here
break;
}
}
MyCanvas.Visibility = Visibility.Collapsed;
MyCanvas.RemoveHandler(MouseLeftButtonUpEvent, new MouseButtonEventHandler(handler));
}
But: In this simple example, you get at about 20 hit elements. But they are sorted in the correct "z-Index". So you can iterate through it and the first interesting element for you is where you could break(Maybe you can do this with LINQ, too). So for me, I know that the first hit TextBox is what I want to focus.
Is this what you need?
BR,
TJ

Why I cannot drop files from explorer to FlowDocumentReader and how to fix it?

I'm trying to implement a piece of functionality that will let the user to drag files into an application to be opened in the FlowDocumentReader.
My problem is that is though I have AllowDrop=true on the FlowDocumentReader, the cursor does not change to the "drop here" icon but changes instead to "drop is not allowed" icon.
This happens only to the FlowDocumentReader, all other parts og the UI (window itself, other controls) work as expected. The FlowDocumentReader actually receives the events, and it is possible to handle the drop, but the user does not have a visual indication that he can release the mouse here.
I also cannot hide the "drop is not allowed" cursor by setting Cursor=Cursors.None
Need to handle DragOver event in FlowDocument to allow dropping here.
xaml:
<!--
<FlowDocumentReader x:Name="fdr" Background="White">
<FlowDocument x:Name="doc" AllowDrop="True" DragEnter="doc_DragOver" Drop="doc_Drop" Background="White"/>
</FlowDocumentReader>
-->
<FlowDocumentReader x:Name="fdr" Background="White">
<FlowDocument x:Name="doc" AllowDrop="True" DragOver="doc_DragOver" Drop="doc_Drop" Background="White"/>
</FlowDocumentReader>
code behind:
private void doc_DragOver(object sender, DragEventArgs e)
{
e.Effects = DragDropEffects.All;
e.Handled = true;
}
private void doc_Drop(object sender, DragEventArgs e)
{
}
I couldn't find any direct way to solve this, so here is what I have ended up with:
I placed a grid on top of the FlowDocumentReader. This grid has a sold color, opacity of 0 (transparent) and Visibility=Collapsed. The purpose of this grid is to serve as a drop target.
When FlowDocument within the FlowDocumentReader received the DragEnter event, I switch the grid's visibility to Visible. The grid starts receiving drag events and the cursor stays in the "drop here" form.
When grid receives Drop or DragLeave events, its visibility is turned back to Collapsed to allow the FlowDocument receive mouse events
<FlowDocumentReader x:Name="fdr" Grid.Row="1" Background="White">
<FlowDocument x:Name="doc" DragEnter="doc_DragEnter" Background="White"/>
</FlowDocumentReader>
<Grid x:Name="dtg" Grid.Row="1" Background="White" Opacity="0"
Drop="dtg_Drop" DragLeave="dtg_DragLeave" Visibility="Collapsed"/>

Resources