如何在WPF(C#)中实现主窗口实时显示子窗口的文件加载状态
Hey there! Let's walk through how to implement this feature in your WPF app. The main challenges here are keeping the UI responsive during file loading and passing real-time status updates from the subwindow to the main window. Here's a step-by-step solution:
Step 1: Define a Custom Event for Loading Progress
First, we'll create an event args class to carry loading status information between windows:
using System; public class FileLoadingEventArgs : EventArgs { public string CurrentFileName { get; } public bool IsCompleted { get; } public FileLoadingEventArgs(string currentFileName, bool isCompleted = false) { CurrentFileName = currentFileName; IsCompleted = isCompleted; } }
Step 2: Implement the SubWindow with Async Loading
In your SubWindow, add an event to broadcast loading progress, then handle file loading asynchronously to avoid freezing the UI:
using System.Collections.Generic; using System.IO; using System.Threading.Tasks; using System.Windows; using System.Windows.Media.Imaging; public partial class SubWindow : Window { // Event to notify main window of loading progress public event EventHandler<FileLoadingEventArgs> FileLoadingProgress; public SubWindow() { InitializeComponent(); Loaded += SubWindow_Loaded; } private async void SubWindow_Loaded(object sender, RoutedEventArgs e) { // Replace this with your actual list of files to load var filesToLoad = new List<string> { @"C:\LocalFiles\image1.jpg", @"C:\LocalFiles\video1.mp4", @"C:\LocalFiles\image2.png" // Add more files here }; foreach (var filePath in filesToLoad) { var fileName = Path.GetFileName(filePath); // Send update to main window about current file OnFileLoadingProgress(new FileLoadingEventArgs(fileName)); // Async load the file (replace with your actual loading logic) await LoadFileAsync(filePath); } // Notify main window all files are done OnFileLoadingProgress(new FileLoadingEventArgs("all files loaded successfully", true)); } private async Task LoadFileAsync(string filePath) { if (filePath.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase) || filePath.EndsWith(".png", StringComparison.OrdinalIgnoreCase)) { // Load image asynchronously await Task.Run(() => { var bitmap = new BitmapImage(); bitmap.BeginInit(); bitmap.UriSource = new Uri(filePath); bitmap.CacheOption = BitmapCacheOption.OnLoad; bitmap.EndInit(); bitmap.Freeze(); // Required to use across threads // Update your Image control on the UI thread Dispatcher.Invoke(() => { // Example: myImageControl.Source = bitmap; }); }); } else if (filePath.EndsWith(".mp4", StringComparison.OrdinalIgnoreCase)) { // Load video via MediaElement await Task.Run(() => { Dispatcher.Invoke(() => { // Example: myMediaElement.Source = new Uri(filePath); }); // Simulate loading time (adjust based on actual video load behavior) await Task.Delay(1000); }); } } // Helper to trigger the progress event protected virtual void OnFileLoadingProgress(FileLoadingEventArgs e) { FileLoadingProgress?.Invoke(this, e); } }
Step 3: Wire Up the Main Window to Receive Updates
In MainWindow, subscribe to the subwindow's progress event and update the TextBlock in real-time:
using System.Windows; public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void OpenSubWindowButton_Click(object sender, RoutedEventArgs e) { var subWindow = new SubWindow(); // Subscribe to the progress event subWindow.FileLoadingProgress += SubWindow_FileLoadingProgress; subWindow.Show(); } private void SubWindow_FileLoadingProgress(object sender, FileLoadingEventArgs e) { // Ensure we update the UI on the main thread Dispatcher.Invoke(() => { StatusTextBlock.Text = e.CurrentFileName; // Optional: Unsubscribe from the event once loading is complete if (e.IsCompleted) { ((SubWindow)sender).FileLoadingProgress -= SubWindow_FileLoadingProgress; } }); } }
Don't forget to set up your MainWindow XAML with the button and text block:
<Window x:Class="YourAppNamespace.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Main Window" Height="300" Width="500"> <StackPanel Margin="20"> <Button x:Name="OpenSubWindowButton" Content="Open Sub Window" Click="OpenSubWindowButton_Click" Margin="0 0 0 15"/> <TextBlock x:Name="StatusTextBlock" FontSize="14" HorizontalAlignment="Left"/> </StackPanel> </Window>
Key Notes to Remember
- Async/Await: Using
async/awaitwithTask.Runkeeps the UI responsive while loading files in the background. - Thread Safety: Always use
Dispatcher.Invokewhen updating UI elements from a background thread (WPF UI elements can only be modified on the main thread). - Image Freezing: When creating
BitmapImagein a background thread, callFreeze()to make it accessible to the UI thread. - Event Cleanup: Unsubscribing from the event after loading completes prevents memory leaks.
内容的提问来源于stack exchange,提问作者Somanna M S

