2011-03-16 161 views
3

我正在使用WPF的OpenFileDialog,我正在寻找一种方法来确保它在显示时在父窗口居中。它似乎缺少可能启用此功能的StartupPosition等明显属性。如何将OpenFileDialog居中放置在WPF的父窗口中?

有人知道秘密吗?

更新:看来,我第一次打开它,它确实出现在父母的中心,但如果我移动它,它会记住它的位置,并且不会在随后的事件中集中打开。

+0

这似乎是我进行快速测试时的默认行为。你能更详细地描述你的情况吗? – 2011-03-16 09:27:11

+0

@Fredrik - 我在问题 – 2011-03-16 09:51:41

+0

中添加了另一个细节我第一次看到一个OP不被接受的问题,它不仅有50分,而且还有如此巨大的差距17.2k,对你很耻辱。 :) – 2015-07-06 14:47:46

回答

0

WPF中的CommonDialog不从窗口类继承,所以它没有StartupPosition属性。

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

+0

谢谢你。你链接到的解决方案是有效地使用WinForms OpenFileDialog,我希望避免。 – 2011-03-16 10:18:31

5

这里是一个泛型类的代码,允许与“次对话”像这样打一处来:

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); 
} 
+0

我可能在这里错过了一些东西,但你似乎正在改变父窗口而不是用OpenFileDialog做任何事情? – 2011-03-16 10:54:50

+0

@Samuel - WM_ENTERIDLE被发送到一个对话框(这里是OpenFileDialog)的所有者,并且lParam arg包含对话框的句柄。你有没有尝试过的代码? – 2011-03-16 11:35:20

+0

还没有尝试过代码 - 只是试图首先理解它。现在你已经解释了WM_ENTERIDLE的意义,这一切都是有道理的。谢谢。 – 2011-03-16 11:41:22