【问题标题】:c# confirmation messagebox during drag and drop freezes file explorerc#在拖放期间确认消息框冻结文件资源管理器
【发布时间】:2016-10-25 23:42:18
【问题描述】:

我有一个带有DataGrid 的窗口,用于存储Document 的对象。当我从文件资源管理器拖放文件时,我将其添加到DataGrid。但是,如果DataGrid 已经包含同名对象,则会显示MessageBox,询问用户是否要替换现有的Document

问题是当显示MessageBox 时,它会冻结文件资源管理器。我无法关闭、最小化等。如果文件资源管理器显示在MessageBox 前面,我必须从任务栏中选择它。我不知道为什么它会冻结文件资源管理器,以及如何修复它。任何帮助都会很棒!

代码:

private void MainWindow_DragEnter(object sender, DragEventArgs e)
{
    gridDragDropVisual.Visibility = Visibility.Visible;
}

private void MainWindow_DragLeave(object sender, DragEventArgs e)
{
    gridDragDropVisual.Visibility = Visibility.Collapsed;
}

private void MainWindow_Drop(object sender, DragEventArgs e)
{
    gridDragDropVisual.Visibility = Visibility.Collapsed;

    // Get dropped data
    if (e.Data.GetDataPresent(DataFormats.FileDrop, false))
    {
        List<string> files = new List<string>();

        foreach (string obj in (string[])e.Data.GetData(DataFormats.FileDrop))
        {
            // If data is a directory
            if (Directory.Exists(obj))
            {
                // Get files in directory
                string[] detectedFiles = Directory.GetFiles(obj, "*.*", SearchOption.AllDirectories);

                // Add files to list
                files.AddRange(detectedFiles);
            }
            else // If data is files
            {
                // Add files to list
                files.Add(obj);
            }
        }

        // Add files as documents
        AddItems(files.ToArray());

        // Populate datagrid
        dataGrid.ItemsSource = documentList = Documents.Get();
    }
}

private void AddItems(string[] items)
{
    foreach (string file in items)
    {
        string fileName = file.Substring(file.LastIndexOf('\\')+1);

        // Create new document
        Document newDocument = new Document(file);

        // Get any existing document with the same name
        Document existingDocument = documentList.FirstOrDefault(objDocument => objDocument.fldName == fileName);

        if (existingDocument != null)
        {
            switch (MessageBox.Show(Application.Current.MainWindow, string.Format("There is already a document that exists with the name '{0}'.\n\nWould you like to replace it?",fileName), "", MessageBoxButton.YesNo, MessageBoxImage.Question))
            {
                case MessageBoxResult.Yes:
                {
                    // Remove existing document
                    Document.Remove(existingDocument.pkDocumentID);

                    // Add document to database
                    newDocument.Add();

                    break;
                }
            }
        }
        else
        {
            // Add document to database
            newDocument.Add();
        }
    }
    // Populate datagrid
    dataGrid.ItemsSource = documentList = Documents.Get();
}

【问题讨论】:

  • 这完全是设计使然。 D+D 通知由拖动源在其调度程序线程上生成。探险家在这种情况下。您的 MessageBox.Show() 调用被阻塞,因此资源管理器无法恢复其调度程序。它看起来会被冻结,不再响应输入。您可以使用自己的 Dispatcher.BeginInvoke() 方法让您的代码在事件处理完成后运行。

标签: c# wpf


【解决方案1】:

问题在于它在同一个线程中运行,因此会暂停其他所有内容。解决方案是让MessageBox 在另一个任务中运行:

/// <summary>
/// Represents a wrapper for using task based messageboxes.
/// </summary>
public static class AdvancedMessageBox
{
    /// <summary>
    /// Does show a messagebox inside another task, so it has rather no impact to the main thread.
    /// </summary>
    public static void TaskBasedShow(
        string message,
        string caption,
        MessageBoxButton buttons,
        MessageBoxImage image)
    {
        Task.Run(() =>
        {
            OnRes?.Invoke(MessageBox.Show(message, caption, buttons, image));
        });
    }

    public delegate void OnResult(MessageBoxResult res);

    /// <summary>
    /// Will get triggered, when the user pressed a button on a messagebox (after calling TaskBasedShow).
    /// </summary>
    public static event OnResult OnRes;
}

实施:

public MainWindow()
{
    InitializeComponent();

    AdvancedMessageBox.OnRes += MessageBox_OnRes;
    AdvancedMessageBox.TaskBasedShow(
        "My message",
        "My caption",
        MessageBoxButton.YesNo,
        MessageBoxImage.Question);
}

/// <summary>
///     Is getting triggered after the user pressed a button.
/// </summary>
/// <param name="res">The pressed button.</param>
private void MessageBox_OnRes(MessageBoxResult res)
{
    // Implement you logic here
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多