diff --git a/Samples/WindowsML/cs-wpf/MainWindow.xaml b/Samples/WindowsML/cs-wpf/MainWindow.xaml index 66aac58fa..37564f094 100644 --- a/Samples/WindowsML/cs-wpf/MainWindow.xaml +++ b/Samples/WindowsML/cs-wpf/MainWindow.xaml @@ -62,6 +62,10 @@ + + + diff --git a/Samples/WindowsML/cs-wpf/MainWindow.xaml.cs b/Samples/WindowsML/cs-wpf/MainWindow.xaml.cs index dbd720ef1..7d797fbf9 100644 --- a/Samples/WindowsML/cs-wpf/MainWindow.xaml.cs +++ b/Samples/WindowsML/cs-wpf/MainWindow.xaml.cs @@ -26,14 +26,27 @@ public partial class MainWindow : Window, IDisposable private OrtEnv? _ortEnv; private List _labels = new(); private bool _disposed; + private bool _isBusy; + private bool _deviceComboWasEnabled; + private bool _epComboWasEnabled; public MainWindow() { InitializeComponent(); // Must match x:Class in XAML Loaded += MainWindow_Loaded; + Closing += MainWindow_Closing; Closed += MainWindow_Closed; } + private void MainWindow_Closing(object? sender, System.ComponentModel.CancelEventArgs e) + { + if (_isBusy) + { + e.Cancel = true; + ResultsTextBox.Text = "Please wait for the current operation to complete before closing."; + } + } + private void MainWindow_Closed(object? sender, EventArgs e) { Dispose(); @@ -133,11 +146,11 @@ private async Task LoadModelAndLabelsAsync() { ModelPath = "SqueezeNet.onnx", EpName = EpCombo.SelectedItem?.ToString(), - DeviceType = (DeviceCombo.IsEnabled ? DeviceCombo.SelectedItem?.ToString() : null), + DeviceType = (DeviceCombo.Items.Count > 1 ? DeviceCombo.SelectedItem?.ToString() : null), PerfMode = GetSelectedPerformanceMode() }; - if (DeviceCombo.IsEnabled && DeviceCombo.SelectedItem == null) + if (DeviceCombo.Items.Count > 1 && DeviceCombo.SelectedItem == null) { ResultsTextBox.Text = "Select a device type for the selected execution provider."; return; @@ -172,8 +185,10 @@ private void SelectImageButton_Click(object sender, RoutedEventArgs e) bitmap.EndInit(); SelectedImage.Source = bitmap; - RunInferenceButton.IsEnabled = true; - ResultsTextBox.Text = "Image selected. Click 'Run Inference' to classify the image."; + RunInferenceButton.IsEnabled = _session != null; + ResultsTextBox.Text = _session != null + ? "Image selected. Click 'Run Inference' to classify the image." + : "Image selected. Load or reload the model first to enable inference."; } catch (Exception ex) { @@ -182,6 +197,34 @@ private void SelectImageButton_Click(object sender, RoutedEventArgs e) } } + private void SetBusy(bool busy) + { + _isBusy = busy; + BusyIndicator.Visibility = busy ? Visibility.Visible : Visibility.Collapsed; + RunInferenceButton.IsEnabled = !busy && _session != null && !string.IsNullOrEmpty(_selectedImagePath); + ReloadSessionButton.IsEnabled = !busy; + SelectImageButton.IsEnabled = !busy; + AllowProviderDownloadCheckBox.IsEnabled = !busy; + PerfModeDefaultRadio.IsEnabled = !busy; + PerfModeMaxPerfRadio.IsEnabled = !busy; + PerfModeMaxEffRadio.IsEnabled = !busy; + + if (busy) + { + // Save combo states before disabling so we can restore them later + _epComboWasEnabled = EpCombo.IsEnabled; + _deviceComboWasEnabled = DeviceCombo.IsEnabled; + EpCombo.IsEnabled = false; + DeviceCombo.IsEnabled = false; + } + else + { + // Restore the combo enabled states that PopulateDeviceCombo computed + EpCombo.IsEnabled = _epComboWasEnabled; + DeviceCombo.IsEnabled = _deviceComboWasEnabled; + } + } + private async void RunInferenceButton_Click(object sender, RoutedEventArgs e) { if (string.IsNullOrEmpty(_selectedImagePath) || _session == null) @@ -192,14 +235,15 @@ private async void RunInferenceButton_Click(object sender, RoutedEventArgs e) try { + SetBusy(true); ResultsTextBox.Text = "Running inference..."; - Dispatcher.Invoke(() => { }, System.Windows.Threading.DispatcherPriority.Render); - var videoFrame = await ImageProcessor.LoadImageFileAsync(_selectedImagePath); + using var videoFrame = await ImageProcessor.LoadImageFileAsync(_selectedImagePath); var inputTensor = await ImageProcessor.PreprocessImageAsync(videoFrame); - using var results = InferenceEngine.RunInference(_session, inputTensor); - var resultTensor = InferenceEngine.ExtractResults(_session, results); + var session = _session; + using var results = await Task.Run(() => InferenceEngine.RunInference(session, inputTensor)); + var resultTensor = InferenceEngine.ExtractResults(session, results); var topPredictions = ResultProcessor.GetTopPredictions(resultTensor, _labels, 5); ResultsTextBox.Text = FormatResultsForUI(topPredictions); @@ -208,6 +252,10 @@ private async void RunInferenceButton_Click(object sender, RoutedEventArgs e) { ResultsTextBox.Text = $"Error during inference: {ex.Message}"; } + finally + { + SetBusy(false); + } } private void PopulateDeviceCombo(OrtEnv env) @@ -258,11 +306,23 @@ private void PopulateDeviceCombo(OrtEnv env) private async void ReloadSessionButton_Click(object sender, RoutedEventArgs e) { - ResultsTextBox.Text = "Loading / reloading model..."; - await LoadModelAndLabelsAsync(); - if (_session != null) + try + { + SetBusy(true); + ResultsTextBox.Text = "Loading / reloading model..."; + await LoadModelAndLabelsAsync(); + if (_session != null) + { + ResultsTextBox.Text += "\nModel loaded. Select an image and click 'Run Inference'."; + } + } + catch (Exception ex) + { + ResultsTextBox.Text = $"Error loading model: {ex.Message}"; + } + finally { - ResultsTextBox.Text += "\nModel loaded. Select an image and click 'Run Inference'."; + SetBusy(false); } }