VS2017 WPF应用:求仅支持本地驱动器选择的C#对话框函数
当然有合适的实现方式啦!针对你在WPF(C#/VS2017)里需要的「仅允许选择本地驱动器」的文件选择功能,我给你整理了两种实用方案,完全贴合你的备份需求:
方案一:基于System.Windows.Forms的FolderBrowserDialog快速实现
这个方案上手快,借助现成的控件就能实现,唯一需要注意的是要添加对应程序集引用:
- 右键你的WPF项目 → 添加引用 → 程序集 → 找到
System.Windows.Forms和System.Drawing并勾选确定。 - 在需要触发选择的事件(比如按钮点击)里添加以下代码:
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




