WPF Window messages not firing while popup window animation is running - wpf

I have created a little Popup window in WPF, which shows and hides with a 500 millisecond fade-animation.
The Popup is shown when the PreviewMouseUp of a TextBox control is fired, and hidden when the focus of the TextBox is lost.
The problem is that if I have two of these TextBoxes, the animation of the Popup-window seems to block all Window Messages sent to the main window while the animation is going. The PreviewMouseUp of the second TextBox is fired only right after the animation of the first TextBox's Popup is complete.
Is there a way to make the fade-animation of my Popup Window NOT to block Window Messages while the animation is running?
Example XAML file:
<Window x:Class="WpfApplication4.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>
<TextBox HorizontalAlignment="Left" Height="23" Margin="22,26,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120" PreviewMouseUp="TextBox_PreviewMouseUp_1" LostFocus="TextBox_LostFocus_1"/>
<TextBox HorizontalAlignment="Left" Height="23" Margin="22,54,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120" PreviewMouseUp="TextBox_PreviewMouseUp_1" LostFocus="TextBox_LostFocus_1"/>
</Grid>
</Window>
Example Code file:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfApplication4
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void TextBox_PreviewMouseUp_1(object sender, MouseButtonEventArgs e)
{
Popup p = new Popup();
p.Width = 100;
p.Height = 100;
p.Placement = PlacementMode.Left;
p.PlacementTarget = (TextBox)sender;
p.Child = new Border();
p.IsOpen = true;
((TextBox)sender).Tag = p;
}
private void TextBox_LostFocus_1(object sender, RoutedEventArgs e)
{
Popup p = (Popup)((TextBox)sender).Tag;
DoubleAnimation anim = new DoubleAnimation(100, 0, new Duration(new TimeSpan(0, 0, 1)));
p.BeginAnimation(WidthProperty, anim);
}
}
}
If you click quickly both textboxes, you notice that the other Popup won't appear (and the textbox doesn't get focus) while the animation is running.
What I have found so far, it seems like if the animation is really intensive (high framefrate), the window messages are blocked until the animation is complete. If I set the application framerate to lower value, like 30FPS, then the problem goes away. But this is not an option for me because I wan't the animations to be as smooth as possible.

This happened because I was animating the margins of the popup window - which generates a lot of window messages when the window size frequently changes. (Which ofcourse jams the whole windows messagepump of the application for the duration of the animation).
So the solution is not to animate the popup itself but a child control of the popup instead (for example a panel), and set the popup to allow transparency so we get the same effect but are actually not animation the actual window size.

Related

WPF MessageBox is not displayed at all if long message is passed

I ran into situation when some MessageBoxes with error messages were not displayed at all. After closer investigation, I was able to narrow down the problem to cases when a very long string is passed as messageBoxText.
In such cases, call MessageBox.Show does not display anything, returns MessageBoxResult.No and, in most cases, there's a message in the Output window saying The thread 0xHEXNUMBER has exited with code 0 (0x0). For me, this method silently fails.
This is very strange - WPF is a very mature technology and I expect this code to work according to spec or throw some exception (e.g. OutOfMemory, StackOverflowException). I've debugged the program and no manged or unmanged exceptions are thrown and caught.
What is the root cause of MessageBox not being displayed? Is there some easy way to debug such things (since no exceptions are thrown or logged). What is the messageBoxText length limit and what does it depend on (I could check that empirically on my computer, but would be conclusive for one OS/platform/.NET Framework version at best)?
Repro:
Here's a code which demonstrates the problem (it can be used with standard WPF Application template in Visual Studio).
MainWindow.xaml:
<Window x:Class="LongMessageInMessageBox.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>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0" Click="ShortMessage_Clicked">Short Message</Button>
<Button Grid.Row="1" Grid.Column="0" Click="LongMessage_Clicked">Long Message</Button>
</Grid>
MainWindow.xaml.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace LongMessageInMessageBox
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
/// Method which shows that displaying short message works correctly
private void ShortMessage_Clicked(object sender, RoutedEventArgs e)
{
Console.WriteLine("ShortMessage_Clicked");
var result = MessageBox.Show("Short Message");
Console.WriteLine(result);
}
/// Method which shows that displaying a long message does not work
private void LongMessage_Clicked(object sender, RoutedEventArgs e)
{
Console.WriteLine("LongMessage_Clicked");
var longTextBuilder = new System.Text.StringBuilder(10000);
longTextBuilder.Append("Long Message \n");
for (int i = 1; i <= 100000; i++)
{
longTextBuilder.Append(" ").Append(i);
}
var result = MessageBox.Show(longTextBuilder.ToString());
Console.WriteLine(result);
}
}
}
Sample from Output window:
ShortMessage_Clicked
OK
ShortMessage_Clicked
OK
LongMessage_Clicked
No
The thread 0x55bc has exited with code 0 (0x0).
MessageBox class in WPF (and WinForms) wraps the Win32 MessageBox function, and doesn't throw an exception. In the old Win32 world error is reported by setting the last-error code, and if you don’t call GetLastError to check, you can just keep going without knowing something is broken.
From Reference Source
//so it just translates the return code to a MessageBoxResult
MessageBoxResult result = Win32ToMessageBoxResult (UnsafeNativeMethods.MessageBox (new HandleRef (null, owner), messageBoxText, caption, style));
I have not tested the capacity of the lpText string in the Win32 MessageBox function. But it is not surprising if the capacity limit is something like 1024, 4096 or 65536, after all, MessageBox function is designed to display short message.

"Help/Tutorial" page in WPF menu bar

I've added a menu bar to application, because I wanted to add there a little tutorial under "Help" menu. Like Help - > "How to use the program", that's the idea.
I would like this to be, a pop up window that has ability to include text, as well as photos to better explain the program. It should be able to have a little bit of formatting (just a simple spaces, tabulator, new lines) so the text with photos looks clean.
To sum up, I need an idea, a tutorial, a guide, an adivce - you name it what should I use to implement those things, because right now I am in a blank spot.
#edit Hope this clarifies my question.
To do this you need menu items:
<Window x:Class="WPFTestApp2.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>
<Menu>
<MenuItem Header="Help">
<MenuItem Header="How to use this program" Click="MenuItem_Click"></MenuItem>
</MenuItem>
</Menu>
</Grid>
</Window>
And you would need a click handler:
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WPFTestApp2
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
HelpWindow window = new HelpWindow();
window.Show();
}
}
}
Then, you would need to create a new window with all the help text you would like. You would need to design that window and I think that is really dependent on what the application does.

XAML link to section of window

In XAML how can I set a hyperlink to take the user to a particular section of my window. Like how you can with anchor tags in HTML. Basically we want the user to be able to click on an error in a list of errors and the link will take them to that area.
XAML Hyperlink NavigateUri could work with a bit of code behind, i.e.
<Window x:Class="fwAnchorInWindow.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel>
<TextBox x:Name="TextBoxName" Text="Enter Name"/>
<TextBox x:Name="TextBoxNumber" Text="Enter Number"/>
<TextBlock>
<Hyperlink NavigateUri="TextBoxName" RequestNavigate="Hyperlink_RequestNavigate">
There is a name error.
</Hyperlink>
</TextBlock>
</StackPanel>
</Window>
using System.Windows;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Navigation;
namespace fwAnchorInWindow
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e)
{
if (sender is Hyperlink)
{
string controlName = ((Hyperlink)sender).NavigateUri.ToString();
IInputElement control = (IInputElement)this.FindName(controlName);
Keyboard.Focus(control);
}
}
}
}
FindName is only one way to find a child control. There are also other ways per this post: WPF ways to find controls.
It is also important to note that WPF distinguishes between Logical Focus and Keybaord Focus: Mark Smith's It's Bascially Focus. In the code above having keyboard focus automatically indicates logical focus.

Show Partial video in MediaElement

I want to use the media element, yet display only part of the video rectangle.
for example : if the video is 100X100 px, i would like to show only the left half of the video, e.g the 50x100 px on the left.
You could place it in a ContentPresenter with negative Margins and ClipToBounds set to true, this will crop the video.
It can be done by setting the Clip property of MediaElement. You can set it to any PathGeometry, below is a simple example.
XAML:
<Window x:Class="Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="378" Width="472">
<Canvas>
<MediaElement LoadedBehavior="Play" Name="myME" Source="c:\\1.wmv" Width="320" Height="240" Canvas.Left="0" Canvas.Top="0">
</MediaElement>
</Canvas>
</Window>
C#
using System;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace tests
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
this.MyMedia1.Clip =
new RectangleGeometry( new Rect(0, 0, myME.Width/3, myME.Height));
}
}
}

Lose focus on textbox when enter is pressed or clicked away

I have a textbox on a canvas. How do I lose the focus (so the caret goes away) when I press enter and/or click on the canvas? My textbox is in a template for a button.
I've tried pretty much everything and it doesn't work:
FocusManager.SetIsFocusScope(mainCanvas, true)
mainCanvas.Focus();
FocusManager.SetFocusedElement(child, parent);
it is interesting that if I use a button it works with KeyBoard.Focus(button) but it doesn't work with a canvas, does anyone know why or have any other suggestion?
The problem with Canvas is that when you click on it, you don't actually get the click event to occur unless you have a background that is not white.
One trick if you want white is to use white -1 or #FFFFFE or if the parent is also white use Transparent. So no one can tell it isn't white.
Now your click event can occur.
Also you need to make it focusable.
MainWindow.xaml
<Window x:Class="TextBoxInCanvas.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 Name="MainGrid">
<Canvas Name="canvas1" Focusable="True" Background="#FFFFFE" MouseDown="canvas1_MouseDown">
<TextBox Height="23" Name="textBox1" Width="120" IsEnabled="True"
Canvas.Left="81" Canvas.Top="115" PreviewKeyDown="textBox1_PreviewKeyDown"/>
</Canvas>
</Grid>
MainWindow.xaml.cs
using System.Windows;
using System.Windows.Input;
namespace TextBoxInCanvas
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void canvas1_MouseDown(object sender, MouseButtonEventArgs e)
{
Keyboard.Focus(canvas1);
}
private void textBox1_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (Key.Enter == e.Key)
Keyboard.Focus(canvas1);
}
}
}
How to make the WPF Canvas mouse click event work?
I made a more complete post on my blog.

Resources