我一直在使用此示例来自定义保存对话框
http://www.codeproject.com/Articles/19566/Extend-OpenFileDialog-and-SaveFileDialog-the-easy
这很好用,我也可以自定义对话框。但是,我看到自定义对话框不遵循基础窗口样式。例如,如果我在Windows 7中,对话框将如下所示,
这是一个来自word的保存对话框,它确实没有像标签和东西这样的选项。但外观与OS保存对话框相同。 但是,带有上述链接的自定义保存对话框将如下所示
为什么不遵循操作系统提供的内容?有没有办法解决这个问题?
好的,我稍微研究了一下,我可以使用Microsoft.WindowsAPICodePack.Dialogs中的CommonSaveFileDialog并创建基础的Save对话框(它与Windows 7样式匹配)。我安装了WindowsAPI shell包,并使用CommonSaveFileDialog控件创建了这样的东西,
以红色标记的控件实际上是CommonFileDialogLabel / CommonFileDialogTextBox / CommonFileDialogComboBox等,它们在这些API中提供。但现在我的问题是如何添加用户控件/自定义控件?我需要完全控制我添加的内容,因此它可以是用户控件。任何想法..请帮助谢谢。
答案 0 :(得分:6)
建议的解决方案如下所述:
“另存为”文件对话框(在此示例中使用)与用户控件相关联,称为CustomSaveFileDialog。它的优点是它存在于工具箱中,并且它自动实现IDisposable接口。但是,它也可能是一个简单的C#类。
此控件具有一个构造函数,该构造函数接受任意特定于应用程序的用户控件,该控件托管将在文件对话框中显示的所有元素。当我得到正确的问题时,这就是所需要的。
CustomSaveFileDialog具有以下属性:
这是所描述的类的代码:
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace customSaveFileDialog
{
public partial class CustomSaveFileDialog : UserControl
{
//https://stackoverflow.com/questions/9665579/setting-up-hook-on-windows-messages
delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType,
IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);
const uint WINEVENT_OUTOFCONTEXT = 0;
[DllImport("user32.dll")]
private static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr
hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess,
uint idThread, uint dwFlags);
[DllImport("user32.dll")]
private static extern bool UnhookWinEvent(IntPtr hWinEventHook);
[DllImport("user32.dll")]
private static extern bool MoveWindow(IntPtr hWnd, int x, int y, int w, int h, bool repaint);
private struct RECT { public int Left; public int Top; public int Right; public int Bottom; }
[DllImport("user32.dll")]
private static extern bool GetClientRect(IntPtr hWnd, out RECT rc);
[DllImport("kernel32.dll")]
private static extern uint GetLastError();
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr SetParent(IntPtr hwndChild, IntPtr hwndNewParent);
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr GetParent(IntPtr hWnd);
private IntPtr hDlg; // Save As dialog handle
private IntPtr hHook; // Event hook
private IntPtr hCtrl; // App. specific user control handle
UserControl ctrl; // App. specific user control
//Static variable containing the instance object
private static CustomSaveFileDialog customSaveFileDialog;
//public property for the user
//theSaveFileDialog has been added to the control in the designer from the Toolbox
public SaveFileDialog Dlg { get { return theSaveFileDialog; } }
//Event hook delegate
private static WinEventDelegate procDelegate = new WinEventDelegate(WinEventProc);
/// <summary>
/// Constructor
/// </summary>
/// <param name="ctrl">The User Control to be displayed in the file dialog</param>
public CustomSaveFileDialog(UserControl ctrl)
{
InitializeComponent();
customSaveFileDialog = this;
this.ctrl = ctrl;
hCtrl = ctrl.Handle;
//Setup Hook; for simplicity, hook all possible events from the current process
hHook = SetWinEventHook(1, 0x7fffffff, IntPtr.Zero,
procDelegate, (uint)Process.GetCurrentProcess().Id, 0, WINEVENT_OUTOFCONTEXT);
}
// Hook function
static void WinEventProc(IntPtr hWinEventHook, uint eventType,
IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
CustomSaveFileDialog csfdg = customSaveFileDialog;
if (csfdg.hDlg == IntPtr.Zero)
csfdg.hDlg = FindWindowEx(IntPtr.Zero, IntPtr.Zero, "#32770", "Save As");
if (hwnd == csfdg.hDlg)
{
IntPtr hParent = GetParent(csfdg.hCtrl);
//this is done only once
if (!(hParent == csfdg.hDlg))
SetParent(csfdg.hCtrl, csfdg.hDlg); //Bind the user control to the Common Dialog
RECT cliRect;
GetClientRect(csfdg.hDlg, out cliRect);
//Position the button in the file dialog
MoveWindow(csfdg.hCtrl, cliRect.Left + 130, cliRect.Bottom - 55, 500, 60, true);
}
}
}
}
关键部分是挂钩事件。这取自that post。
可以注意到,“FindWindowEx”函数(在WinEventProc中)找到标题为“另存为”的所有通用对话框(可能还有更多)。如果这应该是一个问题,则需要更多的过滤,例如通过仅搜索当前线程。可以找到这样的搜索功能here。
此外(上面的代码中未显示)CustormSaveFileDialog.desinger.cs中的“Dispose”方法包含带有hHook句柄作为参数的Unhook函数。
该软件已在Windows7中以调试模式进行测试。作为测试,已经实现了一个带按钮的简单窗体窗口:
//Test for the customized "Save As" dialog
private void button1_Click(object sender, EventArgs e)
{
//Arbitrary User Control
myUserControl ctrl = new myUserControl();
using (CustomSaveFileDialog csfdg = new CustomSaveFileDialog(ctrl))
{
csfdg.Dlg.FileName = "test";
//Show the Save As dialog associated to the CustomFileDialog control
DialogResult res = csfdg.Dlg.ShowDialog();
if (res == System.Windows.Forms.DialogResult.OK)
MessageBox.Show("Save Dialog Finished");
}
}
并且 - 以及测试 - 应用程序特定的用户控件处理以下事件:
using System;
using System.Windows.Forms;
namespace CustomFile
{
public partial class myUserControl : UserControl
{
public myUserControl()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show("Button Clicked");
}
private void pictureBox1_Click(object sender, EventArgs e)
{
MessageBox.Show("Image Clicked");
}
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
if (!checkBox1.Checked)
pictureBox1.Visible = false;
else
pictureBox1.Visible = true;
}
}
}
生成以下输出:
下一张图片显示另一个屏幕截图,文件对话框已调整大小,并且未选中显示图像的复选框。