// -------------------------------------------------------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // -------------------------------------------------------------------------------------------------------------------- namespace Microsoft.Kinect.Toolkit { using System; using System.ComponentModel; using System.Diagnostics; using System.Globalization; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Navigation; using System.Windows.Threading; /// /// Interaction logic for KinectSensorChooserUI.xaml /// public partial class KinectSensorChooserUI : UserControl { /// /// Set this to true when the application is listining for audio input from the sensor. /// UI will show a microphone icon. /// public static readonly DependencyProperty IsListeningProperty = DependencyProperty.Register( "IsListening", typeof(bool), typeof(KinectSensorChooserUI), new PropertyMetadata(false)); /// /// The KinectSensorChooser whose status we are displaying. /// public static readonly DependencyProperty KinectSensorChooserProperty = DependencyProperty.Register( "KinectSensorChooser", typeof(KinectSensorChooser), typeof(KinectSensorChooserUI), new PropertyMetadata(null)); /// /// Used internally to transfer the visual state from the view model to the /// VisualStateManager defined in XAML. /// public static readonly DependencyProperty VisualStateProperty = DependencyProperty.Register( "VisualState", typeof(string), typeof(KinectSensorChooserUI), new PropertyMetadata(null, (o, args) => ((KinectSensorChooserUI)o).OnVisualstateChanged((string)args.NewValue))); /// /// Timer used to check if the mouse is still in the popup when we activated /// the popup with a mouse hover. We do this because the mouse may not be /// in the popup when it comes up and we will never get a mouse leave event. /// private readonly DispatcherTimer popupCloseCheck; private bool suppressPopupOnFocus; private Window parentWindow; /// /// Initializes a new instance of the KinectSensorChooserUI class /// public KinectSensorChooserUI() { Loaded += OnLoaded; Unloaded += OnUnloaded; this.InitializeComponent(); this.popupCloseCheck = new DispatcherTimer( TimeSpan.FromMilliseconds(1000), DispatcherPriority.Normal, this.OnPopupCloseCheckFired, this.Dispatcher); var viewModel = new KinectSensorChooserUIViewModel(); this.layoutRoot.DataContext = viewModel; var visualStateBinding = new Binding("VisualState") { Source = viewModel }; SetBinding(VisualStateProperty, visualStateBinding); var sensorChooserBinding = new Binding("KinectSensorChooser") { Source = this }; BindingOperations.SetBinding(viewModel, KinectSensorChooserUIViewModel.KinectSensorChooserProperty, sensorChooserBinding); var isListeningBinding = new Binding("IsListening") { Source = this }; BindingOperations.SetBinding(viewModel, KinectSensorChooserUIViewModel.IsListeningProperty, isListeningBinding); this.expandedPopup.LayoutUpdated += this.ExpandedPopupOnLayoutUpdated; } /// /// Set this to true when the application is listining for audio input from the sensor. /// UI will show a microphone icon. Value is passed through to the view model. /// public bool IsListening { get { return (bool)this.GetValue(IsListeningProperty); } set { this.SetValue(IsListeningProperty, value); } } /// /// The KinectSensorChooser whose status we are displaying. Value is /// passed through to the view model. /// public KinectSensorChooser KinectSensorChooser { get { return (KinectSensorChooser)this.GetValue(KinectSensorChooserProperty); } set { this.SetValue(KinectSensorChooserProperty, value); } } /// /// Used internally to transfer the visual state from the view model to the /// VisualStateManager defined in XAML. /// public string VisualState { get { return (string)this.GetValue(VisualStateProperty); } set { this.SetValue(VisualStateProperty, value); } } private void OnLoaded(object sender, RoutedEventArgs routedEventArgs) { this.parentWindow = Window.GetWindow(this); if (parentWindow != null) { parentWindow.Deactivated += ParentWindowOnDeactivated; } } private void OnUnloaded(object sender, RoutedEventArgs routedEventArgs) { if (this.parentWindow != null) { parentWindow.Deactivated -= ParentWindowOnDeactivated; } } private void ParentWindowOnDeactivated(object sender, EventArgs eventArgs) { this.ClosePopup(); } private void ClosePopup() { this.expandedPopup.IsOpen = false; } private void OpenPopup() { this.expandedPopup.IsOpen = true; } private void OnRootGridGotKeyboardFocus(object sender, RoutedEventArgs e) { if (!this.suppressPopupOnFocus) { OpenPopup(); } } private void OnRootGridMouseEnter(object sender, MouseEventArgs e) { OpenPopup(); } private void ExpandedPopupOnLayoutUpdated(object sender, EventArgs eventArgs) { // makes the popup top-aligned with its parent this.expandedPopup.VerticalOffset = (this.popupGrid.ActualHeight - this.layoutRoot.ActualHeight - 1.0) / 2.0; } private void ExpandedPopupOnOpened(object sender, EventArgs eventArgs) { this.popupCloseCheck.Stop(); if (this.layoutRoot.IsKeyboardFocusWithin) { Keyboard.Focus(this.popupGrid); } else { this.popupCloseCheck.Start(); } } private void OnExpandedPopupMouseLeave(object sender, MouseEventArgs e) { this.ClosePopup(); } private void OnPopupCloseCheckFired(object sender, EventArgs e) { this.popupCloseCheck.Stop(); if (this.expandedPopup.IsOpen && !this.popupGrid.IsMouseOver && !this.popupGrid.IsKeyboardFocusWithin) { this.ClosePopup(); } } private void OnPopupGridGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) { var oldFocus = e.OldFocus as FrameworkElement; var newFocus = e.NewFocus as FrameworkElement; if (newFocus == this.popupGrid) { if (oldFocus != this.layoutRoot) { // Focus is returning to us after being tabbed around our children. // That is our signal to quit the popup. this.suppressPopupOnFocus = true; this.layoutRoot.Focusable = false; e.Handled = true; // There doesn't seem to be an easy way to generically tell which way the user was // navigating with the keyboard (tab or shift+tab) check if the shift key is pressed FocusNavigationDirection direction = ((Keyboard.Modifiers & ModifierKeys.Shift) != 0) ? FocusNavigationDirection.Previous : FocusNavigationDirection.Next; this.ClosePopup(); this.MoveFocus(new TraversalRequest(direction)); this.layoutRoot.Focusable = true; this.suppressPopupOnFocus = false; } } } private void OnVisualstateChanged(string newState) { VisualStateManager.GoToState(this, newState, true); } private void TellMeMoreLinkRequestNavigate(object sender, RequestNavigateEventArgs e) { var hyperlink = e.OriginalSource as Hyperlink; if (hyperlink != null) { try { // Careful - ensure that this NavigateUri comes from a trusted source, as in this sample, before launching a process using it. Process.Start(new ProcessStartInfo(hyperlink.NavigateUri.ToString())); } catch (Win32Exception) { // No default browser was set to handle the http request or unable to launch the browser MessageBox.Show(string.Format(CultureInfo.CurrentCulture, Properties.Resources.NoDefaultBrowserAvailable, hyperlink.NavigateUri)); } this.ClosePopup(); } e.Handled = true; } } }