We have a custom on-screen keyboard (OSK) form as part of our .NET Windows Forms Application. This keyboard is useful to enter data into a DataGridView and some other textboxes. We want to be able to use it to enter a file name into an OpenFileDialog or SaveFileDialog.
However, when either Dialog shows up, the form containing the OSK stops responding to input. I tried creating a new Form that is used as the OSK's owner. I use the new form and call keyboard.Show(owner). This still doesn't prevent the keyboard from being unable to be used while an OpenFileDialog or SaveFileDialog is in their ShowDialog method.
How can we use an on-screen keyboard form on top of an OpenFileDialog or SaveFileDialog without having the keyboard be hosted in a separate process?
Well, running the OSK window in another process is a fine idea. You get it for free by running osk.exe, provided by Windows. You could technically run it another STA thread but that's a fairly advanced technique, too many ways where the SystemEvents class can seriously ruin your life.
But you can solve the problem with a sliver of code, you just need to re-enable the OSK window right after the dialog is displayed. Elegantly done with the BeginInvoke() method:
private void OpenButton_Click(object sender, EventArgs e) {
this.BeginInvoke(new Action(() => EnableWindow(osk.Handle, true)));
if (openFileDialog1.ShowDialog(this) == DialogResult.OK) {
// etc...
}
}
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern bool EnableWindow(IntPtr hWnd, bool enable);
With the assumption that the osk variable stores a reference to your OSK form.
Related
I'm writing a WPF application and want it to start as a hidden window. I've created the Window object and set its Visibility property to Visibility.Hidden before calling Application.Run(). Then, I have an event handler for Window.Loaded that also sets the visibility to Visibility.Hidden. Between the call to Application.Run() and the callback to OnWindowLoaded(), there is a black outline of the window that flashes up on the screen and then disappears. It's like the window manager is creating a drop shadow for the window or something and then hides it immediately.
After running my project through instrumentation, I finally found that Window.Show() was somehow getting called. So, I looked into the source code at http://www.dotnetframework.org/Search.aspx:
Application.Run() ends up calling a private method named Application.RunInternal().
RunInternal() checks the visibility of the Window object that was passed in to the Run() method.
If the Visibility property is not Visibility.Visible, a call to Window.Show() is made.
I then looked at the source for System.Windows.Window:
Window.Show() sets the Visibility property on itself (the window) to be Visibility.Visible.
Based on this, I don't see how to force the window to stay hidden. By trying to make the window invisible at startup, I'm causing the Application object to call Window.Show(); I don't understand why the Application object even cares about the window's visibility. It's been a frustrating experience... :-(
I've seen other answers that say to not call Application.Run() and to instead set up your own event dispatchers, but that seems like overkill for something that should be easy. I just want the main window to stay hidden, for no "flicker" to appear at app startup, and for the window to become visible when I'm ready for it to do so (which happens later in my application logic).
Can anyone offer a suggestion?
Did you remove the StartupUri entry in App.xaml? If you do, the App class won't instantiate the window for you and show it. You can do this by yourself by overwriting the App.OnStartup method.
Basically, I build a composition root in this OnStartup method and just create a window at the end of the process:
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
// Do your custom initialization code here
MainWindow = new MainWindow();
MainWindow.Show();
}
If you really want to omit the whole application build up process (which I wouldn't recommend, as you won't have features like the fallback to Application Resources), you can create a Dispatcher by yourself using this code:
var dispatcher = Dispatcher.CurrentDispatcher;
var synchronizationContext = new DispatcherSynchronizationContext(dispatcher);
SynchronizationContext.SetSynchronizationContext(synchronizationContext);
Dispatcher.Run();
The comment on this Answer finally led me to find the solution to this issue. I needed to display multiple windows on multiple screens at once, and by minimizing the window it gives me the performance I needed. Thanks.
My addin is written in c#, NetOffice, ExcelDNA using WPFframework. Some part uses winforms, too.
The main UI is WPF
When there is a modal dialog displayed, users force close Excel.
Next time when they launch excel, Excel will say " Excel experienced a serious problem with the '*' add-in. If you have seen this message multiple times, you should disable this add0in and checke to see if an update is available. Do you want to disable this add-in?"
Yes, No
Users usually click Yes or enter without reading the message and then my add-in disappears from Excel.
So I do not want this dialog to show up. Is it possible and how? thanks
I try to catch all exception in AutoOpen() like below. But it seems have no effect to stop the dialog at all.
public void AutoOpen()
{
.....
System.Windows.Forms.Application.ThreadException += ApplicationOnThreadException;
AppDomain.CurrentDomain.UnhandledException += CurrentDomainUnhandledException;
Dispatcher.CurrentDispatcher.UnhandledException += CurrentDispatcher_UnhandledException;
TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
....
}
public void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
{
Helper.LogError(e.Exception);
}
public void ApplicationOnThreadException(object sender, ThreadExceptionEventArgs threadExceptionEventArgs)
{
Helper.LogError(threadExceptionEventArgs.Exception);
}
public void CurrentDomainUnhandledException(object sender, UnhandledExceptionEventArgs args)
{
if (!(args.ExceptionObject is ThreadAbortException))
{
Exception exc = args.ExceptionObject as Exception;
Helper.LogError(exc);
}
}
public void CurrentDispatcher_UnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
Helper.LogError(e.Exception);
e.Handled = true;
}
I presume by 'users force close Excel' you mean the user ends the Excel process from Task Manager or something.
Excel puts some internal guards in place around ribbon handler calls, so that if Excel crashes during a ribbon event handler, Excel knows which add-in was called when the crash happened, to disable next time as you describe. So if Excel is terminated unexpectedly while your modal dialog is shown, your add-in is the one remembered as the 'cause'.
Your attempt at handling unhandled exceptions is not likely to work, since .NET is hosted in a native process (in Excel). So unhandled exceptions which bubble up to Excel won't be returned to the .NET runtime, but will more likely crash the whole Excel process. So trying to handle more exceptions is not likely to help.
Perhaps a modal dialog is not the right approach, since it causes your users to get confused and think Excel has crashed, causing the unexpected termination. At least be sure to set the Excel window as the parent of the modal dialog, so that the dialog stays in front of Excel.
I am having one Windows phone game, built using Silverlight. In this game, I want to add TapJoy. I have downloaded their latest SDK and follow all their steps to intigrate the it within my app.
In the game, I am using silverlight as a main frame work and Global Media Element to play contious Background Music. I am using
(Microsoft.Xna.Framework.Media) (Microsoft.Xna.Framework) namespace.
Using them, I use following methods to play contious background sound.
DispatcherTimer and FrameworkDispatcher.Update
Now, when I click tap joy button to open their offers, they load fine; however, when I open the video within the offer, they show us following error “Video cannot be played, please try again.”
Based on some research and study, I tried few things and found that,
a) I need to set Media Element and DispatcherTimer is to null.
b) The application is sent in background (deactivated) and then I open it again (activated), the video is coming fine. I checked and found that Media Element and DispatcherTimer were set to null properly.
But if I follow step one only, and do not send the app in background, the media element and dispatcherTimer are not set to null.
Can anyone please help me and answer me following
a) Am I doing anythign wroing with this?
b) Can I do anything so that when tap joy button is clicked, my application is sent to background automatically since this can solve the issue.
c) I am using gc.collect() after setting value to null but still it is not getting destroyed.
Thanks in advance,
David Jacob.
I'm trying to follow along with what you've said. I personally would've set it up differently, but I'll get to that later.
I have a setup that is similar to your description, and it works with Tapjoy's Videos.
Firstly, you mentioned that it was a Silverlight game, so I created a new Windows Phone Application project under the Silverlight For Windows Phone template, in VS 2010.
Setup Dispatcher:
I added the following class to my project (typically called XNAFrameworkDispatcherService.cs from this msdn example: http://msdn.microsoft.com/en-us/library/ff842408.aspx)
public class XNAFrameworkDispatcherService : IApplicationService
{
private DispatcherTimer frameworkDispatcherTimer;
public XNAFrameworkDispatcherService()
{
this.frameworkDispatcherTimer = new DispatcherTimer();
this.frameworkDispatcherTimer.Interval = TimeSpan.FromTicks(333333);
this.frameworkDispatcherTimer.Tick += frameworkDispatcherTimer_Tick;
FrameworkDispatcher.Update();
}
void frameworkDispatcherTimer_Tick(object sender, EventArgs e)
{
FrameworkDispatcher.Update();
}
void IApplicationService.StartService(ApplicationServiceContext context)
{
this.frameworkDispatcherTimer.Start();
}
void IApplicationService.StopService()
{
this.frameworkDispatcherTimer.Stop();
}
}
In order to start this service, make sure you've added it to your App.xaml.
Add an attribute to your Application element that points to your namespace, something like this:
xmlns:s="clr-namespace:WindowsPhoneApplication;assembly=WindowsPhoneApplication">
Then within your block add the following:
<s:XNAFrameworkDispatcherService />
Play Music:
Now about playing a looping music file.
In the MainPage.xaml.cs, I've setup a Microsoft.Xna.Framework.Media.Song to loop when the page is navigated to, using the Microsoft.Xna.Framework.Media.MediaPlayer.
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);
Tapjoy.TapjoyConnect.Instance.RequestTapjoyConnect("your-app-id", "your-secret-key");
try
{
Song song = Song.FromUri("example", new Uri("/example.wma", UriKind.Relative));
MediaPlayer.IsRepeating = true;
MediaPlayer.Play(song);
}
catch (Exception)
{
System.Diagnostics.Debug.WriteLine("Can't load sound");
}
}
I also set it to stop playing music, when the page is navigated away from.
protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
MediaPlayer.Stop();
}
I then created a button to launch the Tapjoy Offer wall.
private void button1_Click(object sender, RoutedEventArgs e)
{
Tapjoy.TapjoyConnect.Instance.ShowOffers();
}
Summary:
What happens now, is when your Application starts up, it launches the XNAFrameworkDispatcherService that ticks at approximately 30fps. This will dispatch messages that are in the XNA Framework Queue for you. This is only needed in silverlight applications that are using audio/media services from XNA.
When the MainPage is navigated to, you ping Tapjoy with the Connect call, and you load up your Song to loop.
Normal gameplay can progress now, and when the Show Offers button is clicked, Tapjoy will navigate away from your page, causing on navigated from event to fire, and the MediaPlayer will stop your song.
Ideas for your game:
You might want to consider creating a new project and using the "Windows Phone Silverlight and XNA Application" option. VS2010 will create a blank project with a Content manager already setup, so you can use sounds and images with the XNA pipeline, which I've found to be easier.
Good luck, and remember that Tapjoy provides support for these issues as well. Just email them at support#tapjoy.com, or use the Tapjoy Developer group at: https://groups.google.com/group/tapjoy-developer?hl=en
Is there anyway that I can find out if user has been holding Shift (CTRL or any other key) when she/he double click on application icon from desktop to start the application?
I have a WPF application where I want to be able to detect if the user has been holding any special key when he/she started the application (by double clicking) so I can change some settings if the key was pressed.
I tried :
private void Application_Startup(object sender, StartupEventArgs e)
{
}
but couldn't find any way to detect the key down .
Write this code in your application start-up event:
// Instead of the MessageBox you could write your code here
if ((Keyboard.Modifiers & ModifierKeys.Shift) > 0)
{
MessageBox.Show("Shift Pressed");
}
I think you should look at this question: Keyboard modifiers during application startup This is probably what you're looking for.
Hope it helps.
Should I use ApplicationCommands.Close for closing modal dialog boxes or is that command considered reserved for closing the application? If it is the latter, do folks create Close commands for each Dialog box or just a single Close command for all their modal dialog boxes?
Here is how WPF uses ApplicationCommand.Close:
WPF itself has no built in command handler for ApplicationCommands.Close, but
WPF executes the ApplicationCommand.Close RoutedCommand whenever it receives the Win32 message WM_APPCOMMAND with lParam=APPCOMMAND_CLOSE. This means that if any Win32 application sends you an APPCOMMAND_CLOSE, your ApplicationCommand.Close handler will be called.
The documentation for APPCOMMAND_CLOSE gives this definition:
Close the window (not the application).
I would assume WPF applications should treat ApplicationCommand.Close the same way, and that "the window" would include dialog boxes (it generally does in the world of Win32).
Why do you care about what the Win32 documentation says? It might be important in three situations:
Accessibilty scenarios
Keyboards that have a "close window" key
When the user has configured a combination of mouse buttons to send the "close window" command
So to answer your question: No, ApplicationCommand.Close is not reserved for closing the application. Its purpose is to close the window, including a dialog box window. So there is no need to create separate commands to close dialog boxes.
Many applications simply use a style in App.xaml to set a CommandBinding on thw Window class, and in the handler they end by calling ((Window)sender).Close(). This is a simple and elegant solution.
If you're just looking to bind a button click to close a dialog, you can set the IsCancel property on the button as recommended in the docs:
<Button IsCancel="True">Cancel</Button>
When you click that, it will close the dialog with a false result. If you want to close with a true result, one very simple way is adding a click handler and writing two (2) lines of code-behind. Your XAML is:
<Button IsDefault="True" Click="acceptButton_Click">OK</Button>
And the code-behind:
void acceptButton_Click(object sender, RoutedEventArgs e)
{
this.DialogResult = true;
}
This will close the dialog and return a true result.
Since this is view code (close a window), this code-behind doesn't typically cause me any duress in my strict MVVM architectures. YDMV.
Closing an application is different than closing a dialog.
There is a built in command for dismissing dialogs. There is a big red 'X' at the top of any Window class that you create. When you hit that 'X' you generate a 'DialogCancelCommand' which is then handled by the 'OnDialogCancel' event handler inside the Window class. However, for reasons that are known only inside Redmond, the 'DialogCancelCommand' is an internal RoutedEvent.
I can't speak for other engineers, but I have reproduced the 'DialogCancelCommand' from the Reflected code so that I can close dialog boxes identically to the way the internal commands perform the same operation.
/// <summary>
/// Cancels a dialog.
/// </summary>
public static readonly RoutedCommand DialogCancelCommand = new RoutedCommand("DialogCancel", typeof(CoreCommands));