【问题标题】:How do I center the OpenFileDialog to its parent Window in WPF?如何在 WPF 中将 OpenFileDialog 居中到其父窗口?
【发布时间】:2011-03-16 09:15:32
【问题描述】:

我正在使用 WPF 的 OpenFileDialog,并且我正在寻找一种方法来确保它在显示时位于父窗口的中心。它似乎缺少可能启用此功能的明显属性,例如 StartupPosition。

有人知道这个秘密吗?

更新: 好像第一次打开它确实出现在父级的中心,但是如果我移动它,它就会记住它的位置,并且不会居中打开在以后的场合。

【问题讨论】:

  • 这似乎是我进行快速测试时的默认行为。你能更详细地描述你的场景吗?
  • @Fredrik - 我在问题中添加了另一个细节
  • 我第一次看到一个不被接受的问题,一个 OP 不仅像 50 分,而且还有如此巨大的差距 17.2k,真丢脸。 :)
  • 我有一个后续问题要问你们..stackoverflow.com/questions/61613124/…

标签: wpf openfiledialog


【解决方案1】:

这是一个通用类的代码,它允许像这样玩“子对话框”:

public class SubDialogManager : IDisposable
{
    public SubDialogManager(Window window, Action<IntPtr> enterIdleAction)
        :this(new WindowInteropHelper(window).Handle, enterIdleAction)
    {
    }

    public SubDialogManager(IntPtr hwnd, Action<IntPtr> enterIdleAction)
    {
        if (enterIdleAction == null)
            throw new ArgumentNullException("enterIdleAction");

        EnterIdleAction = enterIdleAction;
        Source = HwndSource.FromHwnd(hwnd);
        Source.AddHook(WindowMessageHandler);
    }

    protected HwndSource Source { get; private set; }
    protected Action<IntPtr> EnterIdleAction { get; private set; }

    void IDisposable.Dispose()
    {
        if (Source != null)
        {
            Source.RemoveHook(WindowMessageHandler);
            Source = null;
        }
    }

    private const int WM_ENTERIDLE = 0x0121;

    protected virtual IntPtr WindowMessageHandler(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        if (msg == WM_ENTERIDLE)
        {
            EnterIdleAction(lParam);
        }
        return IntPtr.Zero;
    }
}

这就是您在标准 WPF 应用程序中使用它的方式。这里我只是复制父窗口大小,但我会让你做中心数学:-)

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        bool computed = false; // do this only once
        int x = (int)Left;
        int y = (int)Top;
        int w = (int)Width;
        int h = (int)Height;
        using (SubDialogManager center = new SubDialogManager(this, ptr => { if (!computed) { SetWindowPos(ptr, IntPtr.Zero, x, y, w, h, 0); computed= true; } }))
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.ShowDialog(this);
        }
    }

    [DllImport("user32.dll")]
    private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, int flags);
}

【讨论】:

  • 我可能在这里遗漏了一些东西,但您似乎正在更改父窗口而不是使用 OpenFileDialog 做任何事情?
  • @Samuel - WM_ENTERIDLE 被发送到对话框(这里是 OpenFileDialog)的所有者,lParam arg 包含对话框的句柄。你试过代码了吗?
  • 还没有尝试过代码 - 只是想先理解它。现在您已经解释了 WM_ENTERIDLE 的意义,这一切都说得通。谢谢。
【解决方案2】:

WPF 中的 CommonDialog 不继承自窗口类,因此它没有 StartupPosition 属性。

查看此博客文章以获取一种解决方案:OpenFileDialog in .NET on Vista
简而言之,它将对话框包装在一个窗口中,然后显示它。

【讨论】:

  • 感谢您。您链接到的解决方案有效地使用了我希望避免的 WinForms OpenFileDialog。
猜你喜欢
  • 2011-08-25
  • 2016-05-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-03
  • 2017-03-18
  • 1970-01-01
  • 2011-08-04
相关资源
最近更新 更多