WPF 多窗口分文件实现方案

发布于:2025-07-19 ⋅ 阅读:(12) ⋅ 点赞:(0)

WPF 多窗口分文件实现方案

项目文件结构

WindowSwitcher/
├── App.xaml
├── App.xaml.cs
├── MainWindow.xaml
├── MainWindow.xaml.cs
├── Views/
│   ├── SettingsWindow.xaml
│   ├── SettingsWindow.xaml.cs
│   ├── DataWindow.xaml
│   ├── DataWindow.xaml.cs
│   ├── HelpWindow.xaml
│   └── HelpWindow.xaml.cs
└── Services/
    └── WindowManager.cs

1. 主窗口 (MainWindow.xaml)

<Window x:Class="WindowSwitcher.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WindowSwitcher"
        Title="窗口切换管理器" Height="450" Width="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        
        <!-- 导航按钮区域 -->
        <StackPanel Grid.Row="0" Orientation="Horizontal" Background="#f0f0f0" Padding="10">
            <Button Content="主窗口" Margin="5" Padding="10,5" Click="ShowMainWindow"/>
            <Button Content="设置窗口" Margin="5" Padding="10,5" Click="ShowSettingsWindow"/>
            <Button Content="数据窗口" Margin="5" Padding="10,5" Click="ShowDataWindow"/>
            <Button Content="帮助窗口" Margin="5" Padding="10,5" Click="ShowHelpWindow"/>
            <Button Content="退出应用" Margin="5" Padding="10,5" Click="ExitApplication" 
                    Background="#ffcccc" Foreground="DarkRed"/>
        </StackPanel>
        
        <!-- 主窗口内容 -->
        <StackPanel Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Center">
            <TextBlock Text="欢迎使用窗口切换管理器" FontSize="24" Margin="0,0,0,20"/>
            <TextBlock Text="{Binding CurrentStatus}" FontSize="18" Foreground="#666"/>
            <Button Content="刷新窗口状态" Margin="0,20,0,0" Padding="10,5" Click="RefreshStatus"/>
        </StackPanel>
    </Grid>
</Window>

2. 主窗口代码 (MainWindow.xaml.cs)

using WindowSwitcher.Services;
using System.Windows;

namespace WindowSwitcher
{
    public partial class MainWindow : Window
    {
        private readonly WindowManager _windowManager = WindowManager.Instance;
        
        public string CurrentStatus => $"当前活动窗口: {_windowManager.ActiveWindow?.Title}";
        
        public MainWindow()
        {
            InitializeComponent();
            DataContext = this;
            
            // 初始化所有窗口
            _windowManager.InitializeWindows();
            
            // 显示主窗口
            _windowManager.ShowWindow<MainWindow>();
        }
        
        // 按钮事件处理
        private void ShowMainWindow(object sender, RoutedEventArgs e) => 
            _windowManager.ShowWindow<MainWindow>();
        
        private void ShowSettingsWindow(object sender, RoutedEventArgs e) => 
            _windowManager.ShowWindow<SettingsWindow>();
        
        private void ShowDataWindow(object sender, RoutedEventArgs e) => 
            _windowManager.ShowWindow<DataWindow>();
        
        private void ShowHelpWindow(object sender, RoutedEventArgs e) => 
            _windowManager.ShowWindow<HelpWindow>();
        
        private void ExitApplication(object sender, RoutedEventArgs e) => 
            Application.Current.Shutdown();
        
        private void RefreshStatus(object sender, RoutedEventArgs e)
        {
            // 刷新数据绑定
            OnPropertyChanged(nameof(CurrentStatus));
        }
        
        // 实现简单的属性变更通知
        public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
        }
    }
}

3. 设置窗口 (Views/SettingsWindow.xaml)

<Window x:Class="WindowSwitcher.Views.SettingsWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="系统设置" Height="400" Width="600">
    <Grid Margin="20">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        
        <TextBlock Grid.Row="0" Text="系统设置" FontSize="20" FontWeight="Bold" Margin="0,0,0,20"/>
        
        <StackPanel Grid.Row="1" Orientation="Horizontal" Margin="0,0,0,10">
            <TextBlock Text="主题:" Width="100" VerticalAlignment="Center"/>
            <ComboBox Width="200">
                <ComboBoxItem Content="浅色主题"/>
                <ComboBoxItem Content="深色主题" IsSelected="True"/>
            </ComboBox>
        </StackPanel>
        
        <StackPanel Grid.Row="2" Orientation="Horizontal" Margin="0,0,0,10">
            <TextBlock Text="语言:" Width="100" VerticalAlignment="Center"/>
            <ComboBox Width="200">
                <ComboBoxItem Content="中文"/>
                <ComboBoxItem Content="English"/>
            </ComboBox>
        </StackPanel>
        
        <StackPanel Grid.Row="3" Orientation="Horizontal" Margin="0,0,0,20">
            <TextBlock Text="自动保存:" Width="100" VerticalAlignment="Center"/>
            <CheckBox IsChecked="True" VerticalAlignment="Center"/>
        </StackPanel>
        
        <Button Grid.Row="4" Content="返回主窗口" HorizontalAlignment="Center" 
                Padding="10,5" Click="ReturnToMain" VerticalAlignment="Bottom"/>
    </Grid>
</Window>

4. 设置窗口代码 (Views/SettingsWindow.xaml.cs)

using System.Windows;
using WindowSwitcher.Services;

namespace WindowSwitcher.Views
{
    public partial class SettingsWindow : Window
    {
        private readonly WindowManager _windowManager = WindowManager.Instance;
        
        public SettingsWindow()
        {
            InitializeComponent();
        }
        
        private void ReturnToMain(object sender, RoutedEventArgs e)
        {
            _windowManager.ShowWindow<MainWindow>();
        }
    }
}

5. 数据窗口 (Views/DataWindow.xaml)

<Window x:Class="WindowSwitcher.Views.DataWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="数据分析" Height="500" Width="700">
    <Grid Margin="15">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        
        <TextBlock Grid.Row="0" Text="数据分析面板" FontSize="20" FontWeight="Bold" Margin="0,0,0,15"/>
        
        <!-- 数据表格 -->
        <DataGrid Grid.Row="1" AutoGenerateColumns="True" ItemsSource="{Binding DataItems}">
            <DataGrid.Columns>
                <DataGridTextColumn Header="ID" Binding="{Binding Id}" Width="Auto"/>
                <DataGridTextColumn Header="名称" Binding="{Binding Name}" Width="*"/>
                <DataGridTextColumn Header="数值" Binding="{Binding Value}" Width="Auto"/>
                <DataGridTextColumn Header="日期" Binding="{Binding Date, StringFormat=yyyy-MM-dd}" Width="Auto"/>
            </DataGrid.Columns>
        </DataGrid>
        
        <StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,15,0,0">
            <Button Content="加载数据" Padding="10,5" Margin="0,0,10,0" Click="LoadData"/>
            <Button Content="返回主窗口" Padding="10,5" Click="ReturnToMain"/>
        </StackPanel>
    </Grid>
</Window>

6. 数据窗口代码 (Views/DataWindow.xaml.cs)

using System.Windows;
using System.Collections.ObjectModel;
using WindowSwitcher.Services;

namespace WindowSwitcher.Views
{
    public partial class DataWindow : Window
    {
        private readonly WindowManager _windowManager = WindowManager.Instance;
        
        // 数据模型
        public class DataItem
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public double Value { get; set; }
            public DateTime Date { get; set; }
        }
        
        // 数据集合
        public ObservableCollection<DataItem> DataItems { get; } = new ObservableCollection<DataItem>();
        
        public DataWindow()
        {
            InitializeComponent();
            DataContext = this;
            
            // 初始加载一些示例数据
            LoadSampleData();
        }
        
        private void LoadSampleData()
        {
            DataItems.Clear();
            
            // 添加示例数据
            DataItems.Add(new DataItem { Id = 1, Name = "项目A", Value = 42.5, Date = DateTime.Now.AddDays(-2) });
            DataItems.Add(new DataItem { Id = 2, Name = "项目B", Value = 78.3, Date = DateTime.Now.AddDays(-1) });
            DataItems.Add(new DataItem { Id = 3, Name = "项目C", Value = 15.2, Date = DateTime.Now });
        }
        
        private void LoadData(object sender, RoutedEventArgs e)
        {
            // 模拟加载更多数据
            int startId = DataItems.Count + 1;
            for (int i = 0; i < 5; i++)
            {
                DataItems.Add(new DataItem 
                {
                    Id = startId + i,
                    Name = $"新增项目{startId + i}",
                    Value = new Random().NextDouble() * 100,
                    Date = DateTime.Now.AddDays(-i)
                });
            }
        }
        
        private void ReturnToMain(object sender, RoutedEventArgs e)
        {
            _windowManager.ShowWindow<MainWindow>();
        }
    }
}

7. 帮助窗口 (Views/HelpWindow.xaml)

<Window x:Class="WindowSwitcher.Views.HelpWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="帮助文档" Height="350" Width="500">
    <Grid Margin="15">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        
        <TextBlock Grid.Row="0" Text="帮助与支持" FontSize="20" FontWeight="Bold" Margin="0,0,0,10"/>
        
        <ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto">
            <TextBlock TextWrapping="Wrap">
                <Run FontWeight="Bold">如何使用窗口切换功能:</Run>
                <LineBreak/>
                1. 点击顶部导航栏中的按钮可在不同窗口间切换
                <LineBreak/>
                2. 每个窗口都提供"返回主窗口"按钮
                <LineBreak/>
                3. 窗口状态会被保留,再次打开时保持上次的状态
                <LineBreak/><LineBreak/>
                
                <Run FontWeight="Bold">常见问题:</Run>
                <LineBreak/>
                Q: 为什么关闭按钮只是隐藏窗口?
                <LineBreak/>
                A: 这是设计选择,为了保持窗口状态并快速切换。要完全退出应用,请使用"退出应用"按钮。
                <LineBreak/><LineBreak/>
                
                <Run FontWeight="Bold">技术支持:</Run>
                <LineBreak/>
                如有任何问题,请联系 support@windowswitcher.com
            </TextBlock>
        </ScrollViewer>
        
        <Button Grid.Row="2" Content="返回主窗口" Padding="10,5" 
                HorizontalAlignment="Center" Margin="0,15,0,0" Click="ReturnToMain"/>
    </Grid>
</Window>

8. 帮助窗口代码 (Views/HelpWindow.xaml.cs)

using System.Windows;
using WindowSwitcher.Services;

namespace WindowSwitcher.Views
{
    public partial class HelpWindow : Window
    {
        private readonly WindowManager _windowManager = WindowManager.Instance;
        
        public HelpWindow()
        {
            InitializeComponent();
        }
        
        private void ReturnToMain(object sender, RoutedEventArgs e)
        {
            _windowManager.ShowWindow<MainWindow>();
        }
    }
}

9. 窗口管理器 (Services/WindowManager.cs)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using WindowSwitcher.Views;

namespace WindowSwitcher.Services
{
    public sealed class WindowManager
    {
        // 单例实例
        private static readonly Lazy<WindowManager> _instance = 
            new Lazy<WindowManager>(() => new WindowManager());
        
        public static WindowManager Instance => _instance.Value;
        
        // 存储所有窗口实例
        private readonly Dictionary<Type, Window> _windows = new Dictionary<Type, Window>();
        
        // 当前活动窗口
        public Window ActiveWindow { get; private set; }

        private WindowManager() { }

        // 初始化所有窗口
        public void InitializeWindows()
        {
            // 创建主窗口
            CreateWindow<MainWindow>();
            
            // 创建其他窗口
            CreateWindow<SettingsWindow>();
            CreateWindow<DataWindow>();
            CreateWindow<HelpWindow>();
        }

        // 创建窗口实例
        private void CreateWindow<T>() where T : Window, new()
        {
            var windowType = typeof(T);
            if (!_windows.ContainsKey(windowType))
            {
                var window = new T();
                window.Closing += OnWindowClosing;
                _windows[windowType] = window;
            }
        }

        // 显示指定类型的窗口
        public void ShowWindow<T>() where T : Window
        {
            var windowType = typeof(T);
            if (_windows.TryGetValue(windowType, out Window window))
            {
                // 隐藏当前活动窗口
                if (ActiveWindow != null && ActiveWindow != window)
                {
                    ActiveWindow.Hide();
                }
                
                // 显示新窗口
                window.Show();
                window.Activate();
                window.Focus();
                ActiveWindow = window;
            }
            else
            {
                // 如果窗口尚未创建,则创建并显示
                CreateWindow<T>();
                ShowWindow<T>();
            }
        }

        // 窗口关闭事件处理
        private void OnWindowClosing(object sender, CancelEventArgs e)
        {
            if (sender is Window window)
            {
                // 阻止实际关闭,改为隐藏
                e.Cancel = true;
                window.Hide();

                // 如果关闭的是当前活动窗口,则激活主窗口
                if (ActiveWindow == window)
                {
                    ShowWindow<MainWindow>();
                }
            }
        }
        
        // 获取特定类型的窗口
        public T GetWindow<T>() where T : Window
        {
            return _windows.TryGetValue(typeof(T), out Window window) ? (T)window : null;
        }
        
        // 关闭所有窗口并退出
        public void ShutdownApplication()
        {
            // 关闭所有窗口
            foreach (var window in _windows.Values)
            {
                window.Closing -= OnWindowClosing;
                window.Close();
            }
            
            _windows.Clear();
            Application.Current.Shutdown();
        }
    }
}

10. 应用程序入口 (App.xaml)

<Application x:Class="WindowSwitcher.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <!-- 全局样式可以放在这里 -->
    </Application.Resources>
</Application>

11. 应用程序入口代码 (App.xaml.cs)

using System.Windows;
using WindowSwitcher.Services;

namespace WindowSwitcher
{
    public partial class App : Application
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);
            
            // 初始化窗口管理器
            var windowManager = WindowManager.Instance;
            windowManager.InitializeWindows();
        }
        
        protected override void OnExit(ExitEventArgs e)
        {
            // 清理资源
            WindowManager.Instance.ShutdownApplication();
            base.OnExit(e);
        }
    }
}

关键实现说明

1. 分文件组织

  • MainWindow:主窗口,作为应用入口
  • Views文件夹:包含所有其他窗口(设置、数据、帮助)
  • Services文件夹:包含窗口管理器服务

2. 窗口管理器核心功能

// 创建窗口
private void CreateWindow<T>() where T : Window, new()
{
    var windowType = typeof(T);
    if (!_windows.ContainsKey(windowType))
    {
        var window = new T();
        window.Closing += OnWindowClosing;
        _windows[windowType] = window;
    }
}

// 切换窗口
public void ShowWindow<T>() where T : Window
{
    // ...
    window.Show();
    window.Activate();
    window.Focus();
    ActiveWindow = window;
}

// 处理关闭事件
private void OnWindowClosing(object sender, CancelEventArgs e)
{
    e.Cancel = true; // 阻止实际关闭
    window.Hide();   // 改为隐藏
}

3. 数据绑定示例

在数据窗口中,展示了如何使用数据绑定:

// 数据模型
public class DataItem
{
    public int Id { get; set; }
    public string Name { get; set; }
    public double Value { get; set; }
    public DateTime Date { get; set; }
}

// 数据集合
public ObservableCollection<DataItem> DataItems { get; } = new ObservableCollection<DataItem>();

// XAML绑定
<DataGrid ItemsSource="{Binding DataItems}">

4. 属性变更通知

在主窗口中实现了简单的属性变更通知:

public string CurrentStatus => $"当前活动窗口: {_windowManager.ActiveWindow?.Title}";

// 刷新方法
private void RefreshStatus(object sender, RoutedEventArgs e)
{
    OnPropertyChanged(nameof(CurrentStatus));
}

// 实现INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

使用说明

  1. 项目结构

    • 创建一个新的WPF应用程序项目
    • 按上述文件结构组织代码
  2. 启动应用

    • 应用程序启动时会初始化所有窗口
    • 主窗口首先显示
  3. 窗口切换

    • 使用顶部导航栏按钮在不同窗口间切换
    • 每个窗口都有返回主窗口的按钮
  4. 关闭窗口

    • 点击关闭按钮实际上是隐藏窗口
    • 使用"退出应用"按钮完全关闭程序
  5. 数据保持

    • 每个窗口的状态在切换时保持不变
    • 数据窗口中的数据在重新打开时保持

这种分文件实现方式使代码结构清晰,便于维护和扩展,同时保持了窗口切换的高性能和状态保持特性。


网站公告

今日签到

点亮在社区的每一天
去签到