wpf OpenFileDialog:按照用户选择文件的顺序加载文件

beq87vna  于 12个月前  发布在  其他
关注(0)|答案(1)|浏览(110)

我将Multiselect设置为true,以便能够同时加载多个文件。问题是它忽略了用户选择文件的顺序,FileNames的列表总是相同的(如果我以不同的顺序选择同一组文件)。
我的问题是:是否有可能实现所需的行为?(存储路径在相同的顺序作为选择).

List<string> filePaths = new List<string>();
Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
dlg.Multiselect = true;
dlg.DefaultExt = ".txt";
// dlg.Filter = my filter //

Nullable<bool> result = dlg.ShowDialog();
if (result == true)
{
    foreach (string file in dlg.FileNames)
    {

    }

}

字符串

zlhcx6iw

zlhcx6iw1#

由于OpenFileDialog是一个密封类,它可能需要以某种形式进行黑客攻击。我个人的黑客攻击方法是使用一个轮询循环,调用P/pocketke,以便在选择文件名时抓取保存文件名的子窗口,当发生变化时,维护一个外部列表,我们称之为NamesInOrder,它是新选择的任何文件名的FIFO。
在这种情况下,我首先选择了B,然后是C和A。
x1c 0d1x的数据

public MainForm()
{
    InitializeComponent();
    StartPosition = FormStartPosition.CenterScreen;
    buttonOpen.Click += (sender, e) =>
    {
        ExecOpenInOrder(sender, e);
        MessageBox.Show(string.Join(Environment.NewLine, NamesInOrder), caption: "Names in Order");
    }; 
}

字符串


显示打开文件对话框的方法

private void ExecOpenInOrder(object? sender, EventArgs e)
{
    NamesInOrder.Clear();
    openFileDialog.Title = OPEN_FILE_TITLE;
    openFileDialog.InitialDirectory =
        Path.Combine(
            Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
            Assembly.GetEntryAssembly().GetName().Name
    );
    Directory.CreateDirectory(openFileDialog.InitialDirectory);
    openFileDialog.Multiselect = true;
    var dialogResult = DialogResult.None;
    localStartPollForChanges();
    openFileDialog.ShowDialog();
    .
    .
    .
}
List<string> NamesInOrder { get; } = new List<string>();

正在检测OpenFileDialog的hWnd

虽然OpenFileDialog的标题默认为“Open”,但调用GetWindowText将返回空,除非我们显式地设置一个可识别的值,在本例中使用const string OPEN_FILE_TITLE = "Open"。一旦我们获得它,我们将枚举它的子窗口。

async void localStartPollForChanges()
    {
        while (dialogResult == DialogResult.None)
        {
            var hWndParent = GetForegroundWindow();
            StringBuilder sb = new StringBuilder(MAX_STRING);
            if (hWndParent != IntPtr.Zero)
            {
                GetWindowText(hWndParent, sb, MAX_STRING);
            }
            Debug.WriteLine($"\nForeground window title: {sb}");
            if (sb.ToString() == OPEN_FILE_TITLE)
            {
                EnumChildWindows(hWndParent, localEnumChildWindowCallback, IntPtr.Zero);
            }
            await Task.Delay(TimeSpan.FromSeconds(0.1));
        }
    }

找到正确的子窗口并读取其文本

我们正在寻找一个类为“ComboBoxEx 32”的子窗口。

bool localEnumChildWindowCallback(IntPtr hWnd, IntPtr lParam)
    {
        StringBuilder className = new StringBuilder(MAX_STRING);
        GetClassName(hWnd, className, MAX_STRING);

        if (className.ToString() == "ComboBoxEx32")
        {
            StringBuilder windowText = new StringBuilder(MAX_STRING);
            GetWindowText(hWnd, windowText, MAX_STRING);

            // Detect multiselect
            var names = localGetNames(windowText.ToString());
            foreach (var name in NamesInOrder.ToArray())
            {
                if(!names.Contains(name))
                {
                    // Remove any names that aren't in new selection
                    NamesInOrder.Remove(name);
                }
            }
            foreach (var name in names.ToArray())
            {
                // If NamesInOrder doesn't already hold the name, add it to the end.
                if (!NamesInOrder.Contains(name))
                {
                    NamesInOrder.Add(name);
                }
            }
            Debug.WriteLine(string.Join(Environment.NewLine, NamesInOrder));
            return false;
        }
        return true;
    }

提取文件名

检索此窗口文本时,请使用RegEx分隔多个文件名,其中名称用引号括起并用空格分隔。

string[] localGetNames(string text)
    {
        string[] names =
                Regex
                .Matches(text.ToString(), pattern: @"""(.*?)\""")
                .Select(_ => _.Value.Trim(@"""".ToCharArray()))
                .ToArray();
        // But it there's only one name, the pattern
        // will never 'hit' so return the single name 
        return names.Any() ? names : new string[] { text };
    }

相关问题