Use UWP UI in WPF Application - c#

I have an application which runs in the background, but i wanted to add a Window with the UWP API.
After adding the References to:
Windows.UI
Windows.UI.Xaml
I tried to start the UWP application with:
Windows.UI.Xaml.Application.Start(p => new UWPApp(); );
In the UWPApp class i added the UWP template code:
using System;
using System.Diagnostics;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
namespace ClipboardSync {
public class UWPApp : Windows.UI.Xaml.Application {
private bool _contentLoaded;
public void InitializeComponent() {
if (_contentLoaded)
return;
_contentLoaded = true;
}
public UWPApp() {
this.InitializeComponent();
this.Suspending += OnSuspending;
}
protected override void OnLaunched(LaunchActivatedEventArgs e) {
Frame rootFrame = Window.Current.Content as Frame;
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (rootFrame == null) {
// Create a Frame to act as the navigation context and navigate to the first page
rootFrame = new Frame();
rootFrame.NavigationFailed += OnNavigationFailed;
if (e.PreviousExecutionState == ApplicationExecutionState.Terminated) {
//TODO: Load state from previously suspended application
}
// Place the frame in the current Window
Window.Current.Content = rootFrame;
}
if (e.PrelaunchActivated == false) {
if (rootFrame.Content == null) {
// When the navigation stack isn't restored navigate to the first page,
// configuring the new page by passing required information as a navigation
// parameter
rootFrame.Navigate(typeof(MainPage), e.Arguments);
}
// Ensure the current window is active
Window.Current.Activate();
}
}
/// <summary>
/// Invoked when Navigation to a certain page fails
/// </summary>
/// <param name="sender">The Frame which failed navigation</param>
/// <param name="e">Details about the navigation failure</param>
void OnNavigationFailed(object sender, NavigationFailedEventArgs e) {
throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
}
/// <summary>
/// Invoked when application execution is being suspended. Application state is saved
/// without knowing whether the application will be terminated or resumed with the contents
/// of memory still intact.
/// </summary>
/// <param name="sender">The source of the suspend request.</param>
/// <param name="e">Details about the suspend request.</param>
private void OnSuspending(object sender, SuspendingEventArgs e) {
var deferral = e.SuspendingOperation.GetDeferral();
//TODO: Save application state and stop any background activity
deferral.Complete();
}
}
}
but the new UWPApp Instance is never created and there is no error message.
Is there some kind of restriction so that I can't start a UWP Application inside a WPF App?

UPDATE 1/31/2019
Coming back to this to update my answer. As of Windows 10 update 1809 (build 17763+) this is now supported. More information and samples here:
https://blogs.windows.com/buildingapps/2018/11/02/xaml-islands-a-deep-dive-part-1/
Old answer - pre-1809
This is not supported today. Windows.UI.XAML.* can currently only be used in UWP app processes.
However, at BUILD2017 earlier this year it was announced that support for this is planned in a future update of Windows 10:
https://channel9.msdn.com/Events/Build/2017/B8100

Related

Why async await operation is still time consuming

I have a Winforms application where I am trying to print a pdf document which has multiple layers on it.
But the problem is, This all operation are running on UI thread and it is hanging the UI(not responding) for long time.
I know, this is happening because of UI thread is blocked so, I have tried to make this operation asynchronous by the help of powerful async/await keyword but still my long running method is not being asynchronous. It is not coming forward from the await tasks and still opearation is taking the same time as like synchronous operation.
What I tried:
Please see below:
/// <summary>
/// Show Print Dialog
/// </summary>
private void ShowPrintDialog()
{
// Initialize print dialog
System.Windows.Controls.PrintDialog prtDialog = new System.Windows.Controls.PrintDialog();
prtDialog.PageRangeSelection = PageRangeSelection.AllPages;
prtDialog.UserPageRangeEnabled = false;
_printOptions.PrintQueue = null;
_printOptions.PrintTicket = null;
Enabled = false;
// if there is a default printer then set it
string defaulPrinter = prtDialog.PrintQueue == null ? string.Empty : prtDialog.PrintQueue.FullName;
// Display the dialog. This returns true if the user selects the Print button.
if (prtDialog.ShowDialog() == true)
{
_printOptions.PrintQueue = prtDialog.PrintQueue;
_printOptions.PrintTicket = prtDialog.PrintTicket;
_printOptions.UseDefaultPrinter = (defaulPrinter == prtDialog.PrintQueue.FullName);
}
// Re-enable the form
Enabled = true;
}
/// <summary>
/// Event raised when user clicks Print
/// </summary>
/// <param name="sender">Source of the event</param>
/// <param name="e">Event specific arguments</param>
private void cmdOk_Click(object sender, EventArgs e)
{
ShowPrintDialog();
if (_printOptions.PrintTicket != null)
{
//Set search Options
_print.ExportDataItem = true;
_print.FileName = SearchTemplateName;
//shows progress bar form.
using (frmPrintSearchResultsProgress frmProgress =
new frmPrintSearchResultsProgress(_print, this, _printOptions))
{
frmProgress.ShowDialog(this);
}
if (_print.ExportDataItem && !_print.DataItemExported && !_print.CancelExport)
{
MessageBox.Show("No Document printed.");
}
}
//Store selected options for current user
SaveOptions();
if (!SkipExport)
Close();
}
/// <summary>
/// Event raised when progress form is shown.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void frmExportSearchResultsProgress_Shown(object sender, EventArgs e)
{
try
{
Application.DoEvents();
dispatcher = Dispatcher.CurrentDispatcher;
// record export/print job start time
_startedUtc = DateTime.UtcNow;
_print.WritingToPdfIndicator = lblWritingPdfFile;
lblProgress.Text = Properties.Resources.PrintSearchResults;
await dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(DoDataItemPrint));
}
}
/// <summary>
/// Prints the selected data items.
/// </summary>
private void DoDataItemPrint()
{
// LONG RUNNING OPERATIONS..
// THIS OPERATION IS BLOCKING THE UI.
}
So, as per mentioned in above code when I opened the PringDialogForm then it is opening a Progress Bar form to see the progress of printing the document and from here frmExportSearchResultsProgress_Shown() event is fired and inside it, I am calling the DoDataItemPrint() method which is time consuming.
So, I tried to make frmExportSearchResultsProgress_Shown event as async/await but still operation is taking the same time as previous.
Can anyone please suggest me where I am doing wrong?
your frmExportSearchResultsProgress_Shown method starts on the UI thread
it then dispatches DoDataItemPrint to the ... same UI thread
it schedules a continuation (via await) so that when that incomplete thing happens, we get back into frmExportSearchResultsProgress_Shown, and since there's probably a sync-context in play here, the sync-context capture (implicit in await) would push us to ... the UI thread
As you can see: everything is happening on the UI thread.
If you want to not block the UI, you need to get off the UI thread. That could be as simple as using Task.Run to invoke DoDataItemPrint, but without knowing what that code contains, it is impossible to know whether you're using thread-bound controls to do the printing. If you are... it will be hard to get away from that.

How can I get the "touchscreen keyboard" in a Windows 10 tablet to stop opening twice in our WPF app?

Please note that I have spent a lot of time searching through online posts including on SO but have been unsuccessful so far.
The problem is with the touchscreen keyboard that started being opened automatically because of the Windows 10 Touch Keyboard and Handwriting Panel Service whenever somebody clicks on a textbox whereas before with Windows 8.1 the keyboard was opened only due to the C# API calls from within our Structures Asset Management (SAM) app. Thus with Windows 10, the virtual keyboard was being opened twice whenever someone clicks on a textbox-—once because of the SAM C# API call and once due to the Touch Keyboard and Handwriting Panel Service.
Please note that we have attempted to disable the Touch Keyboard and Handwriting Panel Service but that then causes the touchscreen keyboard to not appear at all.
Normally, it would be fine to just let the OS open this touchscreen keyboard using the Touch Keyboard and Handwriting Panel Service but the problem is we need to sometimes show the touchscreen keyboard and other times show only a numeric keypad, so just relying on the Windows service is not an option.
Here are the classes that worked successfully for controlling the keyboard in Windows 8.1:
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Input;
namespace Cpr.Apps.Sam.Controls
{
/// <summary>
/// Shows or hides the touch keyboard on tablets.
/// </summary>
public class TouchKeyboard
{
/// <summary>
/// The touch keyboard app's file path.
/// </summary>
private static string _touchKeyboardAppFilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonProgramFiles), #"Microsoft Shared\ink\TabTip.exe");
/// <summary>
/// Set to true if the app is currently running on a touch device and false otherwise.
/// </summary>
private static bool _isTouchScreen = Tablet.TabletDevices.Cast<TabletDevice>().Any(tabletDevice => tabletDevice.Type == TabletDeviceType.Touch);
/// <summary>
/// The keyboard visible flag.
/// </summary>
/// <remarks>
/// This flag only keeps track of the keyboard's visibility if it was set using this class.
/// </remarks>
private static bool _isKeyboardVisible;
/// <summary>
/// The delay after which the keyboard will be hidden, in seconds.
/// </summary>
/// <remarks>
/// The keyboard is not hidden immediately when the associated input field loses the keyboard focus, so that it will
/// not flicker if another input field with this behavior obtains the keyboard focus immediately afterwards.
/// </remarks>
private const double KEYBOARD_HIDE_DELAY = 0.25;
/// <summary>
/// The number of milliseconds per second. Used for time conversions.
/// </summary>
private const long MILLISECONDS_PER_SECOND = 1000;
/// <summary>
/// True if the current device has a touch screen and false otherwise.
/// </summary>
public static bool IsTouchScreen
{
get { return _isTouchScreen; }
}
/// <summary>
/// Shows the touch keyboard if the app is running on a touch device.
/// </summary>
/// <remarks>
/// This method does nothing if the app is not currently running on a touch device.
/// </remarks>
public static void Show()
{
// check if the app is running on a touch device
if (_isTouchScreen && _touchKeyboardAppFilePath != null)
{
try
{
// launch the touch keyboard app
Process.Start(_touchKeyboardAppFilePath);
// set the keyboard visible flag
_isKeyboardVisible = true;
}
catch (Exception)
{
// do nothing
}
}
}
/// <summary>
/// Hides the touch keyboard if the app is running on a touch device.
/// </summary>
/// <remarks>
/// This method does nothing if the app is not currently running on a touch device.
/// </remarks>
public static void Hide()
{
// check if the app is running on a touch device
if (_isTouchScreen)
{
// reset the keyboard visible flag
_isKeyboardVisible = false;
// hide the keyboard after a delay so that if another input field with this behavior obtains the focus immediately,
// the keyboard will not flicker
Timer timer = null;
timer = new Timer((obj) =>
{
// check if the keyboard should still be hidden
if (!_isKeyboardVisible)
{
// check if the keyboard is visible
var touchKeyboardWindowHandle = FindWindow("IPTip_Main_Window", null);
if (touchKeyboardWindowHandle != _nullPointer)
{
// hide the keyboard
SendMessage(touchKeyboardWindowHandle, WM_SYSCOMMAND, SC_CLOSE, _nullPointer);
}
}
// release the timer
timer.Dispose();
}, null, (long)(KEYBOARD_HIDE_DELAY * MILLISECONDS_PER_SECOND), Timeout.Infinite);
}
}
// Win32 null pointer parameter
private static IntPtr _nullPointer = new IntPtr(0);
// Win32 command from the Window menu
private const uint WM_SYSCOMMAND = 0x0112;
// Win32 command to close a window
private static IntPtr SC_CLOSE = new IntPtr(0xF060);
// Win32 API to get a window reference
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
private static extern IntPtr FindWindow(string sClassName, string sAppName);
// Win32 API to send a message to a window
[DllImport("user32.dll", EntryPoint = "SendMessage", SetLastError = true)]
private static extern IntPtr SendMessage(IntPtr hWnd, uint uMsg, IntPtr wParam, IntPtr lParam);
}
}
And:
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interactivity;
using Cpr.Apps.Sam.Controls;
namespace Cpr.Apps.Sam.Styles.Behaviors
{
/// <summary>
/// Behavior that shows the touch keyboard (on tablets only) when the associated control gets the keyboard focus.
/// </summary>
public class ControlShowTouchKeyboardOnFocusBehavior : Behavior<Control>
{
protected override void OnAttached()
{
base.OnAttached();
// add the event handlers
WeakEventManager<Control, KeyboardFocusChangedEventArgs>.AddHandler(AssociatedObject, "GotKeyboardFocus", OnGotKeyboardFocus);
WeakEventManager<Control, KeyboardFocusChangedEventArgs>.AddHandler(AssociatedObject, "LostKeyboardFocus", OnLostKeyboardFocus);
}
/// <summary>
/// Called when the associated control receives the keyboard focus.
/// </summary>
/// <param name="sender">The object triggering this event.</param>
/// <param name="e">The event parameters.</param>
private void OnGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
// show the touch keyboard
TouchKeyboard.Show();
var textBox = sender as TextBox;
if (textBox != null)
textBox.SelectionStart = Math.Max(0, textBox.Text.Length); //Move the caret to the end of the text in the text box.
}
/// <summary>
/// Called when the associated control loses the keyboard focus.
/// </summary>
/// <param name="sender">The object triggering this event.</param>
/// <param name="e">The event parameters.</param>
private void OnLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
// hide the touch keyboard
TouchKeyboard.Hide();
}
}
}
Basically, my question is, how can I make the touchscreen keyboard in Windows 10 behave the same way it did in Windows 8.1? Are there some configuration values I can change on the OS settings, or do I need to change something in the registry? What are the differences between the Touch Panel and Handwriting Service in Windows 8.1 and Windows 10? TIA.
UPDATE:
Please note that I have explored using the "On Screen Keyboard" which I believe is based on COM instead of the newer "Touchscreen Keyboard" but that did not help because ultimately because this COM keyboard requires admin privileges to close or minimize it. This is what I attempted with the "On Screen Keyboard":
using System;
using System.Diagnostics;
using System.Linq;
using System.Management;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interactivity;
using Cpr.Apps.Sam.Controls;
namespace Cpr.Apps.Sam.Styles.Behaviors
{
/// <summary>
/// Behavior that shows the touch keyboard (on tablets only) when the associated control gets the keyboard focus.
/// </summary>
public class ControlShowTouchKeyboardOnFocusBehavior : Behavior<Control>
{
[DllImport("User32")]
private static extern int ShowWindow(int hwnd, int nCmdShow);
private const int SW_HIDE = 0;
private const int SW_RESTORE = 9;
private int hWnd;
private readonly string _USB = "USB";
private readonly string _keyboard = #"osk.exe";
private Process _keyboardProcess = null;
private ProcessStartInfo _startInfo = null;
protected override void OnAttached()
{
base.OnAttached();
// add the event handlers
WeakEventManager<Control, KeyboardFocusChangedEventArgs>.AddHandler(AssociatedObject, "GotKeyboardFocus", OnGotKeyboardFocus);
WeakEventManager<Control, KeyboardFocusChangedEventArgs>.AddHandler(AssociatedObject, "LostKeyboardFocus", OnLostKeyboardFocus);
}
private bool GetKeyboardPresent()
{
bool flag = false;
foreach (ManagementBaseObject managementBaseObject in new ManagementObjectSearcher("Select * from Win32_Keyboard").Get())
{
foreach (PropertyData property in managementBaseObject.Properties)
{
if (Convert.ToString(property.Value).Contains(this._USB))
{
flag = true;
break;
}
}
}
return flag;
}
/// <summary>
/// Called when the associated control receives the keyboard focus.
/// </summary>
/// <param name="sender">The object triggering this event.</param>
/// <param name="e">The event parameters.</param>
private void OnGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
// show the touch keyboard
// TouchKeyboard call here not needed in Windows 10 because of “Touch Keyboard and Handwriting Panel Service” causes virtual keyboard to show up twice. Use on screen keyboard instead.
//TouchKeyboard.Show();
if (!this.GetKeyboardPresent())
{
//_keyboardProcess.StartInfo.WindowStyle = ProcessWindowStyle.Maximized;
Process[] pocesses = Process.GetProcessesByName(_keyboard);
if (pocesses.Any())
{
foreach (var proc in pocesses)
{
hWnd = (int) proc.MainWindowHandle;
ShowWindow(hWnd, SW_RESTORE);
}
}
else
{
_startInfo = new ProcessStartInfo(_keyboard);
_keyboardProcess = new Process
{
EnableRaisingEvents = true,
StartInfo = _startInfo
};
_keyboardProcess.Exited += new EventHandler(ProcessExited);
//Don't need this because it is for parent process: AppDomain.CurrentDomain.ProcessExit += (a, b) => _keyboardProcess.Kill();
_keyboardProcess.Start();
}
}
var textBox = sender as TextBox;
if (textBox != null)
textBox.SelectionStart = Math.Max(0, textBox.Text.Length); //Move the caret to the end of the text in the text box.
}
/// <summary>
/// Called when the associated control loses the keyboard focus.
/// </summary>
/// <param name="sender">The object triggering this event.</param>
/// <param name="e">The event parameters.</param>
private void OnLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
// hide the touch keyboard
// TouchKeyboard call here not needed in Windows 10 because of “Touch Keyboard and Handwriting Panel Service” causes virtual keyboard to show up twice. Use on screen keyboard instead.
//TouchKeyboard.Hide();
if (!GetKeyboardPresent() && _keyboardProcess != null)
{
//Keyboard doesn't minimize if I call Kill() or SW_HIDE, and instead this simply causes the textbox to lose focus so commented out this code
//Process[] pocesses = Process.GetProcessesByName("osk");
//for (int i = 0; i < pocesses.Count(); i++)
//{
// var proc = pocesses[i];
// proc.StartInfo.WindowStyle = ProcessWindowStyle.Minimized;
//hWnd = (int)proc.MainWindowHandle;
//ShowWindow(hWnd, SW_HIDE);
//}
//Task.Delay(500);
}
}
private void ProcessExited(object sender, System.EventArgs e)
{
Debug.WriteLine("Exited _keyboardProcess");
_keyboardProcess = null;
}
}
}
UPDATE 2:
It looks like I may need to port my app from WPF to WinRT to get it to work on Windows 10: See https://learn.microsoft.com/en-us/windows/uwp/porting/ where it says
Move from WPF and Silverlight to WinRT
in
Related Topics
Ended up using a custom WPF software keyboard built in C# instead of the Windows “Touch Keyboard and Handwriting Panel Service” Touchscreen Keyboard and the Onscreen Keyboard.

Getting error "does not contain a definition for" when running on Phone

i'm building my first UWP app but i'm having an issue. When i build and run my app on my computer - build for x86 - it all runs just fine. But when i try to run it on my Windows Phone (ARM), i get the following error:
this.RootSplitView.DisplayMode error CS1061: 'App' does not contain a
definition for 'RootSplitView' and no extension method 'RootSplitView'
accepting a first argument of type 'App' could be found (are you
missing a using directive or an assembly reference?)
This is the .cs file:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
namespace Conquer_Companion
{
using Views;
using Windows.ApplicationModel.Core;
using Windows.UI;
using Windows.UI.ViewManagement;
/// <summary>
/// Provides application-specific behavior to supplement the default Application class.
/// </summary>
sealed partial class App : Application
{
/// <summary>
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
/// </summary>
public App()
{
this.InitializeComponent();
this.Suspending += OnSuspending;
}
/// <summary>
/// Invoked when the application is launched normally by the end user. Other entry points
/// will be used such as when the application is launched to open a sp ecific file.
/// </summary>
/// <param name="e">Details about the launch request and process.</param>
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
#if DEBUG
if (System.Diagnostics.Debugger.IsAttached)
{
// This just gets in the way.
//this.DebugSettings.EnableFrameRateCounter = true;
}
#endif
// Change minimum window size
ApplicationView.GetForCurrentView().SetPreferredMinSize(new Size(350, 200));
CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar = true;
// Darken the window title bar using a color value to match app theme
ApplicationViewTitleBar titleBar = ApplicationView.GetForCurrentView().TitleBar;
if (titleBar != null)
{
//titleBar.ExtendViewIntoTitleBar = true;
titleBar.ButtonBackgroundColor = Colors.Transparent;
titleBar.ButtonInactiveBackgroundColor = Colors.Transparent;
Color titleBarColor = (Color)App.Current.Resources["SystemChromeHighColor"];
titleBar.ButtonForegroundColor = titleBarColor;
}
if (SystemInformationHelpers.IsTenFootExperience)
{
// Apply guidance from https://msdn.microsoft.com/windows/uwp/input-and-devices/designing-for-tv
ApplicationView.GetForCurrentView().SetDesiredBoundsMode(ApplicationViewBoundsMode.UseCoreWindow);
this.Resources.MergedDictionaries.Add(new ResourceDictionary
{
Source = new Uri("ms-appx:///Styles/TenFootStylesheet.xaml")
});
}
AppShell shell = Window.Current.Content as AppShell;
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (shell == null)
{
// Create a AppShell to act as the navigation context and navigate to the first page
shell = new AppShell();
// Set the default language
shell.Language = Windows.Globalization.ApplicationLanguages.Languages[0];
shell.AppFrame.NavigationFailed += OnNavigationFailed;
if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
//TODO: Load state from previously suspended application
}
}
// Place our app shell in the current Window
Window.Current.Content = shell;
if (shell.AppFrame.Content == null)
{
// When the navigation stack isn't restored, navigate to the first page
// suppressing the initial entrance animation.
shell.AppFrame.Navigate(typeof(LandingPage), e.Arguments, new Windows.UI.Xaml.Media.Animation.SuppressNavigationTransitionInfo());
}
// Ensure the current window is active
Window.Current.Activate();
}
/// <summary>
/// Invoked when Navigation to a certain page fails
/// </summary>
/// <param name="sender">The Frame which failed navigation</param>
/// <param name="e">Details about the navigation failure</param>
void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
{
throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
}
/// <summary>
/// Invoked when application execution is being suspended. Application state is saved
/// without knowing whether the application will be terminated or resumed with the contents
/// of memory still intact.
/// </summary>
/// <param name="sender">The source of the suspend request.</param>
/// <param name="e">Details about the suspend request.</param>
private void OnSuspending(object sender, SuspendingEventArgs e)
{
var deferral = e.SuspendingOperation.GetDeferral();
//TODO: Save application state and stop any background activity
deferral.Complete();
}
}
}
And the Xaml:
<Application
x:Class="Conquer_Companion.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Conquer_Companion"
RequestedTheme="Light">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ms-appx://Styles/Styles.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
Can you guys help me figure out whats causing this?
Thanks in advance!

UWP SpeechRecognizer throw exception:Operation is not valid due to the current state of the object

I am developing UWP and want to use SpeechRecognizer. When I run the application, the first try is right but next tries will throw a System.InvalidOperationException at
SpeechRecognitionResult speechRecognitionResult = await speechRecognizer.RecognizeAsync();.
The error message is
"Operation is not valid due to the current state of the object."
And another situation is that when I click the button to speak, the function RecognizeAsync() seems not to be called and I immediately get the MessageDialog with blank content and the return value of the program is 1(0x1). I don't get exception in this way but if I click the button quickly, it will throw the exception above.
I have searched a lot of pages online but none of them could figure out
this problem. Any help will be greatly appreciated. Thanks.
Here is my full code
public sealed partial class VoiceMainPage : Page
{
public VoiceMainPage()
{
InitializeComponent();
}
private async void OnListenAsync(object sender, RoutedEventArgs e)
{
// Create an instance of SpeechRecognizer.
var speechRecognizer = new SpeechRecognizer();
// Compile the dictation grammar by default.
await speechRecognizer.CompileConstraintsAsync();
// Start recognition.
SpeechRecognitionResult speechRecognitionResult = await speechRecognizer.RecognizeAsync();
var messageDialog = new MessageDialog(speechRecognitionResult.Text, "Text spoken");
await messageDialog.ShowAsync();
}
}
Check this official sample code. Here is an adaptation of your code reusing part of the github sample :
public class VoiceMainPage
{
private SpeechRecognizer speechRecognizer;
private CoreDispatcher dispatcher;
private IAsyncOperation<SpeechRecognitionResult> recognitionOperation;
public VoiceMainPage()
{
InitializeComponent();
}
/// <summary>
/// When activating the scenario, ensure we have permission from the user to access their microphone, and
/// provide an appropriate path for the user to enable access to the microphone if they haven't
/// given explicit permission for it.
/// </summary>
/// <param name="e">The navigation event details</param>
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
// Save the UI thread dispatcher to allow speech status messages to be shown on the UI.
dispatcher = CoreWindow.GetForCurrentThread().Dispatcher;
bool permissionGained = await AudioCapturePermissions.RequestMicrophonePermission();
if (permissionGained)
{
// Enable the recognition buttons.
await InitializeRecognizer(SpeechRecognizer.SystemSpeechLanguage);
buttonOnListen.IsEnabled = true;
}
else
{
// Permission to access capture resources was not given by the user; please set the application setting in Settings->Privacy->Microphone.
buttonOnListen.IsEnabled = false;
}
}
private async void OnListenAsync(object sender, RoutedEventArgs e)
{
buttonOnListen.IsEnabled = false;
// Start recognition.
try
{
recognitionOperation = speechRecognizer.RecognizeAsync();
SpeechRecognitionResult speechRecognitionResult = await recognitionOperation;
// If successful, display the recognition result.
if (speechRecognitionResult.Status == SpeechRecognitionResultStatus.Success)
{
// Access to the recognized text through speechRecognitionResult.Text;
}
else
{
// Handle speech recognition failure
}
}
catch (TaskCanceledException exception)
{
// TaskCanceledException will be thrown if you exit the scenario while the recognizer is actively
// processing speech. Since this happens here when we navigate out of the scenario, don't try to
// show a message dialog for this exception.
System.Diagnostics.Debug.WriteLine("TaskCanceledException caught while recognition in progress (can be ignored):");
System.Diagnostics.Debug.WriteLine(exception.ToString());
}
catch (Exception exception)
{
var messageDialog = new Windows.UI.Popups.MessageDialog(exception.Message, "Exception");
await messageDialog.ShowAsync();
}
buttonOnListen.IsEnabled = true;
}
/// <summary>
/// Ensure that we clean up any state tracking event handlers created in OnNavigatedTo to prevent leaks.
/// </summary>
/// <param name="e">Details about the navigation event</param>
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
if (speechRecognizer != null)
{
if (speechRecognizer.State != SpeechRecognizerState.Idle)
{
if (recognitionOperation != null)
{
recognitionOperation.Cancel();
recognitionOperation = null;
}
}
speechRecognizer.StateChanged -= SpeechRecognizer_StateChanged;
this.speechRecognizer.Dispose();
this.speechRecognizer = null;
}
}
/// <summary>
/// Initialize Speech Recognizer and compile constraints.
/// </summary>
/// <param name="recognizerLanguage">Language to use for the speech recognizer</param>
/// <returns>Awaitable task.</returns>
private async Task InitializeRecognizer(Language recognizerLanguage)
{
if (speechRecognizer != null)
{
// cleanup prior to re-initializing this scenario.
speechRecognizer.StateChanged -= SpeechRecognizer_StateChanged;
this.speechRecognizer.Dispose();
this.speechRecognizer = null;
}
// Create an instance of SpeechRecognizer.
speechRecognizer = new SpeechRecognizer(recognizerLanguage);
// Provide feedback to the user about the state of the recognizer.
speechRecognizer.StateChanged += SpeechRecognizer_StateChanged;
// Add a web search topic constraint to the recognizer.
var webSearchGrammar = new SpeechRecognitionTopicConstraint(SpeechRecognitionScenario.WebSearch, "webSearch");
speechRecognizer.Constraints.Add(webSearchGrammar);
// Compile the constraint.
SpeechRecognitionCompilationResult compilationResult = await speechRecognizer.CompileConstraintsAsync();
if (compilationResult.Status != SpeechRecognitionResultStatus.Success)
{
buttonOnListen.IsEnabled = false;
}
/// <summary>
/// Handle SpeechRecognizer state changed events by updating a UI component.
/// </summary>
/// <param name="sender">Speech recognizer that generated this status event</param>
/// <param name="args">The recognizer's status</param>
private async void SpeechRecognizer_StateChanged(SpeechRecognizer sender, SpeechRecognizerStateChangedEventArgs args)
{
await dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
MainPage.Current.NotifyUser("Speech recognizer state: " + args.State.ToString(), NotifyType.StatusMessage);
});
}
}
The button buttonOnListen shall have its enable state set to false during the speech recognition procedure to prevent click handler reentrance. In addition it is preferrable to have the SpeechRecognizer object initialized once during page navigation landing (OnNavigatedTo) and dispose it while leaving the page (OnNavigatedFrom)

Changing frame in windows store app using MVVM

I'm making a windows store app with c#. Inside my MainPage i have a frame. My button is binded to a RelayCommand, and when the user clicks the button, the frame should change AddMovie frame. Why wont it change the frame? My frame is binded to a Frame property in my viewmodel.
private Frame _frame;
public Frame Frame
{
get { return _frame; }
set
{
_frame = value;
OnPropertyChanged();
}
}
In Constructor
_frame = new Frame();
NavToCommand = new RelayCommand(() =>
{
Frame.Navigate(typeof(AddMovie));
});
Make sure that the frame you are using for navigation in your MainPage is the same your app is using as the content for it's current window.
Usually you don't need to create a new frame in your MainPage. Instead it is set in the App.xaml.cs in a method that looks like this:
/// <summary>
/// Invoked when the application is launched normally by the end user. Other entry points
/// will be used such as when the application is launched to open a specific file.
/// </summary>
/// <param name="e">Details about the launch request and process.</param>
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
Frame rootFrame = Window.Current.Content as Frame;
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (rootFrame == null)
{
// Create a Frame to act as the navigation context and navigate to the first page
rootFrame = new Frame();
rootFrame.NavigationFailed += OnNavigationFailed;
if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
//TODO: Load state from previously suspended application
}
// Place the frame in the current Window
Window.Current.Content = rootFrame;
}
if (e.PrelaunchActivated == false)
{
if (rootFrame.Content == null)
{
// When the navigation stack isn't restored navigate to the first page,
// configuring the new page by passing required information as a navigation
// parameter
rootFrame.Navigate(typeof(MainPage), e.Arguments);
}
// Ensure the current window is active
Window.Current.Activate();
}
}
You can inject the rootFrame in your MainPage at that stage and use it for navigation purposes instead of creating a new instance.
However, if you would like to use Navigation with MVVM, check out how to implement the NavigationService pattern in my other answer here:
https://stackoverflow.com/a/38362370/1008758

Categories