How to focus in WPF with WindowsFormHost - wpf

I have this simple setup:
<StackPanel>
<TextBox Text="wpf1" PreviewLostKeyboardFocus="TextBox_PreviewLostKeyboardFocus" />
<TextBox Text="wpf2" PreviewLostKeyboardFocus="TextBox_PreviewLostKeyboardFocus" />
<WindowsFormsHost>
<wf:TextBox Text="winforms" />
</WindowsFormsHost>
</StackPanel>
private void TextBox_PreviewLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
e.Handled = true;
}
Three textboxes, two WPF and one WinForm. I can't move focus between the two WPF-Textboxes which I desired but I can move focus to the WinForm-Textbox. The event PreviewLostKeyboardFocus does not even triggered when moving from a WPF-Textbox to a WinForm-Textbox. Any clues to why and how this could be solved?
EDIT
I've noticed that WindowsFormsHost.PreviewGotKeyboardFocus is triggered first when focus is leaving the WindowsFormsHost again. Thats odd. Maybe it's a bug?

Related

WPF scrolling parent container through child container

I'm having some issues trying to figure out how to scroll the content of a grid which is contained inside of a scroll viewer. When trying to scroll with the mouse wheel or pan (with a touch screen), the grid scrolls fine if the mouse/touch point is over an empty area, but if it is above certain controls (ex. a group box) it won't scroll. Is there some property I'm missing to allow the child panels to allow them to scroll their parent containers?
EDIT:
I incorrectly stated my original layout. Here's a simplified version of my senario:
<Grid>
<ScrollViewer Name="MainScrollViewer">
<StackPanel>
<ListBox /> <--Doesn't Scroll-->
<Button /> <--Scrolls Fine-->
<TextBlock /> <--Scrolls Fine-->
<TextBox /> <--Scrolls Fine-->
<DataGrid /> <--Doesn't Scroll-->
</StackPanel>
</ScrollViewer>
</Grid>
A coworker pointed out that my issue is due to the fact the controls such as a ListBoxes and DataGrids contain ScrollViewers themselves, this makes sense. His suggestion (which would work but we both agree seems more complex than it should be) is to catch and rethrow the the scroll event in the code behind (and likely have to deal with calculating the smount of offset to scroll) so that it can bubble up to "MainScrollViewer".
EDIT 2:
It seems like the only way to achieve this is to use code behind to handle the PreviewMouseWheel event in the parent. That works, but how do I go about implementing the same thing for panning (scrolling by finger on a touch screen)?
Create a bubbling scrollbehavior for your scrollview:
using System.Windows;
using System.Windows.Input;
using System.Windows.Interactivity;
public sealed class BubbleScrollEvent : Behavior<UIElement>
{
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.PreviewMouseWheel += AssociatedObject_PreviewMouseWheel;
}
protected override void OnDetaching()
{
AssociatedObject.PreviewMouseWheel -= AssociatedObject_PreviewMouseWheel;
base.OnDetaching();
}
void AssociatedObject_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
if (!e.Handled)
{
e.Handled = true;
var e2 = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta) { RoutedEvent = UIElement.MouseWheelEvent };
AssociatedObject.RaiseEvent(e2);
}
}
}
Add this behavior to your scrollviewer:
<ScrollViewer x:Name="Scroller">
<i:Interaction.Behaviors>
<ViewAddons:BubbleScrollEvent />
</i:Interaction.Behaviors>
Use ScrollViewer's PreviewMouseWheel event and ScrollToVerticalOffset method...
private void ScrollViewerOnPreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
var scv = sender as ScrollViewer;
if (scv == null) return;
scv.ScrollToVerticalOffset(scv.VerticalOffset - e.Delta);
e.Handled = true;
}
For Starters, be sure you are using the Tech that already exists. That may resolve your issue.
<Grid HorizontalAlignment="Left" Height="300" Margin="10,10,0,0" VerticalAlignment="Top" Width="497" ScrollViewer.VerticalScrollBarVisibility="Visible" />
Although if that doesn't resolve the issue, and i know this sounds strange, Set the background color of the grid AND problem object to #00000000. (if it is not already assigned a color/brush)
<Grid HorizontalAlignment="Left" Height="300" Margin="10,10,0,0" VerticalAlignment="Top" Width="497" Background="#00000000"/>
I know its strange, but when I have these problems it works every time. I have no idea why it works. Something to do with transparency.

How to make TextChanged happen for copy/paste for TextBox in Silverlight?

For silverlight control TextBox, when copy/paste content for TextBox Text property, TextChanged Event not happening.
How to make paste same as typing for Text in TextBox?
Sorry, I can't reproduce this.
I used the following XAML
<StackPanel>
<TextBox TextChanged="TextBox_TextChanged" />
<TextBlock x:Name="tbk" />
</StackPanel>
and the following event handler
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
tbk.Text += "X";
}
Every time I typed in the TextBox or pasted text into it, the TextBlock gained another X.

RadioButton Uncheck events not firing in WPF?

In my WPF Window i have RadioButton with default IsChecked property is true.
How to write code for Uncheck the RadioButton.
I tried with Sipmle example.
I take one radiobutton.
<Grid>
<RadioButton Height="16" Margin="54,103,104,0" GroupName="t" Name="radioButton1" VerticalAlignment="Top" IsChecked="True" Unchecked="radioButton1_Unchecked">Text</RadioButton>
</Grid>
private void radioButton1_Unchecked(object sender, RoutedEventArgs e)
{
radioButton1.IsChecked = false;
}
But its not working
Can any one help on this?
Ramki
First of all, it is not possible to uncheck a radiobutton that is singled out. It would make no sense. That's why your event doesn't get fired.
Now, having a single RadioButton will not help you achieve anything: they are meant to be in a group of RadioButtons. Use a CheckBox instead.
Then in the UnChecked event, you don't have to uncheck it: the event is fired because it was unchecked in the first place =)
<Grid>
<CheckBox Height="16" Margin="54,103,104,0" GroupName="t" Name="checkBox1"
VerticalAlignment="Top" IsChecked="True" Unchecked="checkBox1_Unchecked">Text</CheckBox>
</Grid>
private void checkBox1_Unchecked(object sender, RoutedEventArgs e)
{
MessageBox.Show("checkBox1 has been unchecked!");
}
you can't Uncheck a radiobutton if you haven"t another to check !

Is there any way to alias commands in WPF?

Is there any way to effectively "alias" commands in WPF ? My situation is this : I've created an application that uses ApplicationCommands.Delete in the context of a graphical editor that has a number of customized canvases. Some of the controls that are on these canvases use TextBoxes, but here's the problem : TextBox doesn't respond to ApplicationCommands.Delete, it responds to EditorCommands.Delete. Is there any way to cleanly get TextBox to respond to ApplicationCommands.Delete without subclassing or manually setting bindings on every TextBox instance ?
To answer your specific question, I know of no way to cause two separate routed commands to be treated as the same command. But because ApplicationCommands.Delete is a routed command, after it is delivered to its target, the TextBox and there is no command binding, it will begin bubbling up. So the simplest solution that meets your requirements is to install a command binding for ApplicationCommands.Delete somewhere inbetween the TextBox all the way up to and possibly including the Window, that implements the behavior you desire.
Here's an example that installs a handler on a parent Grid that sends the "right" command the the focused element which in this case will be a TextBox:
<Grid>
<Grid.CommandBindings>
<CommandBinding Command="ApplicationCommands.Delete" CanExecute="CommandBinding_CanExecute" Executed="CommandBinding_Executed"/>
</Grid.CommandBindings>
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="_Edit">
<MenuItem Header="_Delete" Command="ApplicationCommands.Delete"/>
</MenuItem>
</Menu>
<StackPanel>
<TextBox Text="Some text"/>
</StackPanel>
</DockPanel>
</Grid>
and here's the code-behind:
private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
EditingCommands.Delete.Execute(null, Keyboard.FocusedElement);
}

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