You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

VS2017 WPF应用:求仅支持本地驱动器选择的C#对话框函数

当然有合适的实现方式啦!针对你在WPF(C#/VS2017)里需要的「仅允许选择本地驱动器」的文件选择功能,我给你整理了两种实用方案,完全贴合你的备份需求:

方案一:基于System.Windows.Forms的FolderBrowserDialog快速实现

这个方案上手快,借助现成的控件就能实现,唯一需要注意的是要添加对应程序集引用:

  1. 右键你的WPF项目 → 添加引用 → 程序集 → 找到System.Windows.FormsSystem.Drawing并勾选确定。
  2. 在需要触发选择的事件(比如按钮点击)里添加以下代码:
using System.Windows.Forms;
using System.IO;
using System;

private void SelectLocalDrive_Click(object sender, RoutedEventArgs e)
{
    using (var driveDialog = new FolderBrowserDialog())
    {
        // 设置对话框根目录为「此电脑」
        driveDialog.RootFolder = Environment.SpecialFolder.MyComputer;
        driveDialog.Description = "请选择本地固定驱动器";
        // 隐藏「新建文件夹」按钮,避免用户创建无关目录
        driveDialog.ShowNewFolderButton = false;

        if (driveDialog.ShowDialog() == DialogResult.OK)
        {
            string selectedPath = driveDialog.SelectedPath;
            // 验证选中的是不是本地固定驱动器
            var driveInfo = new DriveInfo(selectedPath);
            if (driveInfo.DriveType == DriveType.Fixed && driveInfo.IsReady)
            {
                // 这里拿到的路径就可以直接用于备份操作了
                MessageBox.Show($"已选中本地驱动器:{selectedPath}");
                // 你的备份逻辑写在这里,比如调用Directory.Copy()复制内容
            }
            else
            {
                MessageBox.Show("请选择可用的本地固定驱动器!");
            }
        }
    }
}
方案二:自定义WPF风格的驱动器选择对话框

如果不想引入WinForms控件,或者想要更贴合WPF的UI风格,可以自己写一个自定义对话框,完全控制显示内容:

第一步:创建对话框的XAML(DriveSelectionDialog.xaml)

<Window x:Class="YourNamespace.DriveSelectionDialog"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="选择本地驱动器" Height="300" Width="300" WindowStartupLocation="CenterOwner">
    <Grid>
        <TreeView x:Name="DriveTreeView" Margin="10" SelectedItemChanged="DriveTreeView_SelectedItemChanged">
            <TreeView.ItemTemplate>
                <HierarchicalDataTemplate ItemsSource="{Binding SubFolders}">
                    <StackPanel Orientation="Horizontal">
                        <Image Width="20" Height="20" Source="{Binding Icon}" />
                        <TextBlock Margin="5,0" Text="{Binding DisplayName}" />
                    </StackPanel>
                </HierarchicalDataTemplate>
            </TreeView.ItemTemplate>
        </TreeView>
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,0,10,10" VerticalAlignment="Bottom">
            <Button x:Name="OKBtn" Content="确定" Width="75" Margin="5" IsEnabled="False" Click="OKBtn_Click"/>
            <Button Content="取消" Width="75" Margin="5" Click="CancelBtn_Click"/>
        </StackPanel>
    </Grid>
</Window>

第二步:编写对话框的后台逻辑(DriveSelectionDialog.xaml.cs)

using System.Collections.Generic;
using System.IO;
using System.Windows;
using System.Windows.Media.Imaging;

namespace YourNamespace
{
    public partial class DriveSelectionDialog : Window
    {
        // 暴露选中的驱动器路径给外部调用
        public string SelectedDrivePath { get; private set; }

        public DriveSelectionDialog()
        {
            InitializeComponent();
            LoadLocalDrives();
        }

        // 加载所有可用的本地固定驱动器
        private void LoadLocalDrives()
        {
            var driveItems = new List<DriveItem>();
            foreach (var drive in DriveInfo.GetDrives())
            {
                // 只筛选本地固定且就绪的驱动器
                if (drive.DriveType == DriveType.Fixed && drive.IsReady)
                {
                    driveItems.Add(new DriveItem
                    {
                        DisplayName = $"{drive.Name} ({drive.VolumeLabel})",
                        Path = drive.Name,
                        Icon = GetDriveIcon(drive)
                    });
                }
            }
            DriveTreeView.ItemsSource = driveItems;
        }

        // 获取驱动器的系统图标
        private BitmapImage GetDriveIcon(DriveInfo drive)
        {
            var systemIcon = System.Drawing.Icon.ExtractAssociatedIcon(drive.RootDirectory.FullName);
            var bitmap = systemIcon.ToBitmap();
            var bitmapImage = new BitmapImage();

            using (var stream = new MemoryStream())
            {
                bitmap.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
                stream.Position = 0;
                bitmapImage.BeginInit();
                bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
                bitmapImage.StreamSource = stream;
                bitmapImage.EndInit();
            }
            return bitmapImage;
        }

        // 限制只能选择驱动器节点,不允许进入子文件夹
        private void DriveTreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            var selectedItem = e.NewValue as DriveItem;
            OKBtn.IsEnabled = selectedItem != null && selectedItem.SubFolders.Count == 0;
            if (OKBtn.IsEnabled)
            {
                SelectedDrivePath = selectedItem.Path;
            }
        }

        private void OKBtn_Click(object sender, RoutedEventArgs e)
        {
            DialogResult = true;
            Close();
        }

        private void CancelBtn_Click(object sender, RoutedEventArgs e)
        {
            DialogResult = false;
            Close();
        }
    }

    // 用于绑定TreeView的数据模型
    public class DriveItem
    {
        public string DisplayName { get; set; }
        public string Path { get; set; }
        public BitmapImage Icon { get; set; }
        public List<DriveItem> SubFolders { get; set; } = new List<DriveItem>();
    }
}

第三步:在主窗口调用自定义对话框

private void OpenCustomDriveDialog_Click(object sender, RoutedEventArgs e)
{
    var driveDialog = new DriveSelectionDialog();
    if (driveDialog.ShowDialog() == true)
    {
        string targetDrive = driveDialog.SelectedDrivePath;
        MessageBox.Show($"已选中本地驱动器:{targetDrive}");
        // 执行备份逻辑,例如:
        // Directory.Copy(sourcePath, targetPath, true);
    }
}
额外提示:备份操作的注意事项

拿到驱动器路径后,你可以用Directory.Copy()来复制整个驱动器的内容,但要注意:

  • 异步执行:备份大文件时建议用Task.Run()或者BackgroundWorker,避免UI卡顿;
  • 异常处理:添加try-catch块处理权限不足、文件被占用、磁盘空间不足等异常;
  • 覆盖确认:如果目标路径已有文件,Directory.Copy()的第三个参数设为true会直接覆盖,需要提前给用户提示。

内容的提问来源于stack exchange,提问作者Josh Pulda

火山引擎 最新活动