自定义 OpenFileDialog 修改按钮文字
Customizing OpenFileDialog to modify button text
我想要一个文件夹对话框来获取所选文件夹的路径,并希望将多个文件保存到该路径。
我可以使用 WindowsApiCodePack
得到这个
我想将按钮 "Select folder" 中的文本重命名为 "Save",这是我的客户建议的,除了更改之外没有其他方法可以满足他们的要求。
但是,我可以更改对话框的标题,但不能更改按钮文本。
如何修改按钮文字?
这应该可行
var dialog = new CommonOpenFileDialog();
dialog.IsFolderPicker = true;
dialog.SetOpenButtonText("SAVE TO THIS FOLDER");
如果您使用的是 this 版本的包,那么我认为没有简单的开箱即用解决方案。可以做到,但需要一些反射才能起作用(如果有人找到更简单的方法,请分享)。
首先,您必须在您的项目中引用 System.Windows.Forms
程序集(如果您还没有)。
然后,你至少mock-use了一次,所以方法GetReferencedAssemblies()
returns就可以了(再说一次,如果你无论如何都用它,你可以跳过这一步),下面一行代码就足够了:
Form f=null;
现在,这是一个 class 有几个方法可以使必要的反思更容易:
public class MyReflector
{
string myNamespace;
Assembly myAssembly;
public MyReflector(string assemblyName, string namespaceName)
{
myNamespace = namespaceName;
myAssembly = null;
var alist=Assembly.GetExecutingAssembly().GetReferencedAssemblies();
foreach (AssemblyName aN in alist)
{
if (aN.FullName.StartsWith(assemblyName))
{
myAssembly = Assembly.Load(aN);
break;
}
}
}
public Type GetType(string typeName)
{
Type type = null;
string[] names = typeName.Split('.');
if (names.Length > 0)
type = myAssembly.GetType(myNamespace + "." + names[0]);
for (int i = 1; i < names.Length; ++i)
{
type = type.GetNestedType(names[i], BindingFlags.NonPublic);
}
return type;
}
public object Call(Type type, object obj, string func, object[] parameters)
{
MethodInfo methInfo = type.GetMethod(func, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
return methInfo.Invoke(obj, parameters);
}
public object GetField(Type type, object obj, string field)
{
FieldInfo fieldInfo = type.GetField(field, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
return fieldInfo.GetValue(obj);
}
}
最后,设置按钮文本的代码。
CommonOpenFileDialog ofp = new CommonOpenFileDialog();
ofp.IsFolderPicker = true;
// In the CommonFileDialog in WindowsAPICodePack, there is a nativeDialog field of type IFileDialog
// get it first and check if it's not null:
var r1 = new MyReflector("Microsoft.WindowsAPICodePack", "Microsoft.WindowsAPICodePack");
Type typeCommonFileDialog = typeof(CommonFileDialog);
object nativeDialog = r1.GetField(typeCommonFileDialog, ofp, "nativeDialog");
if (nativeDialog == null)
{
// if nativeDialog was null, initialize it:
r1.Call(ofp.GetType(), ofp, "InitializeNativeFileDialog", new object[]{});
nativeDialog = r1.Call(ofp.GetType(), ofp, "GetNativeFileDialog", new object[] { });
}
// call SetOkButtonLabel method on nativeDialog object
var r2 = new MyReflector("System.Windows.Forms", "System.Windows.Forms");
Type typeIFileDialog = r2.GetType("FileDialogNative.IFileDialog");
r2.Call(typeIFileDialog, nativeDialog, "SetOkButtonLabel",new object[] { "Save" });
ofp.ShowDialog();
解释:
在 WindowsAPICodePack
中,CommonOpenFileDialog
是 CommonFileDialog
class 的子 class。在 CommonFileDialog
中,有一个类型为 IFileDialog
的 nativeDialog
字段(类型 IFileDialog
也不是 public)。您可以使用它来设置按钮的文本。可悲的是,它是私人的。它在仅调用构造函数后也不会初始化(尽管有些方法会初始化它,因此您必须在开始时检查它是否为 null)。 IFileDialog
有一个内部方法 SetOkButtonLabel
。这就是你需要的。
我想要一个文件夹对话框来获取所选文件夹的路径,并希望将多个文件保存到该路径。
我可以使用 WindowsApiCodePack
得到这个我想将按钮 "Select folder" 中的文本重命名为 "Save",这是我的客户建议的,除了更改之外没有其他方法可以满足他们的要求。
但是,我可以更改对话框的标题,但不能更改按钮文本。
如何修改按钮文字?
这应该可行
var dialog = new CommonOpenFileDialog();
dialog.IsFolderPicker = true;
dialog.SetOpenButtonText("SAVE TO THIS FOLDER");
如果您使用的是 this 版本的包,那么我认为没有简单的开箱即用解决方案。可以做到,但需要一些反射才能起作用(如果有人找到更简单的方法,请分享)。
首先,您必须在您的项目中引用 System.Windows.Forms
程序集(如果您还没有)。
然后,你至少mock-use了一次,所以方法GetReferencedAssemblies()
returns就可以了(再说一次,如果你无论如何都用它,你可以跳过这一步),下面一行代码就足够了:
Form f=null;
现在,这是一个 class 有几个方法可以使必要的反思更容易:
public class MyReflector
{
string myNamespace;
Assembly myAssembly;
public MyReflector(string assemblyName, string namespaceName)
{
myNamespace = namespaceName;
myAssembly = null;
var alist=Assembly.GetExecutingAssembly().GetReferencedAssemblies();
foreach (AssemblyName aN in alist)
{
if (aN.FullName.StartsWith(assemblyName))
{
myAssembly = Assembly.Load(aN);
break;
}
}
}
public Type GetType(string typeName)
{
Type type = null;
string[] names = typeName.Split('.');
if (names.Length > 0)
type = myAssembly.GetType(myNamespace + "." + names[0]);
for (int i = 1; i < names.Length; ++i)
{
type = type.GetNestedType(names[i], BindingFlags.NonPublic);
}
return type;
}
public object Call(Type type, object obj, string func, object[] parameters)
{
MethodInfo methInfo = type.GetMethod(func, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
return methInfo.Invoke(obj, parameters);
}
public object GetField(Type type, object obj, string field)
{
FieldInfo fieldInfo = type.GetField(field, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
return fieldInfo.GetValue(obj);
}
}
最后,设置按钮文本的代码。
CommonOpenFileDialog ofp = new CommonOpenFileDialog();
ofp.IsFolderPicker = true;
// In the CommonFileDialog in WindowsAPICodePack, there is a nativeDialog field of type IFileDialog
// get it first and check if it's not null:
var r1 = new MyReflector("Microsoft.WindowsAPICodePack", "Microsoft.WindowsAPICodePack");
Type typeCommonFileDialog = typeof(CommonFileDialog);
object nativeDialog = r1.GetField(typeCommonFileDialog, ofp, "nativeDialog");
if (nativeDialog == null)
{
// if nativeDialog was null, initialize it:
r1.Call(ofp.GetType(), ofp, "InitializeNativeFileDialog", new object[]{});
nativeDialog = r1.Call(ofp.GetType(), ofp, "GetNativeFileDialog", new object[] { });
}
// call SetOkButtonLabel method on nativeDialog object
var r2 = new MyReflector("System.Windows.Forms", "System.Windows.Forms");
Type typeIFileDialog = r2.GetType("FileDialogNative.IFileDialog");
r2.Call(typeIFileDialog, nativeDialog, "SetOkButtonLabel",new object[] { "Save" });
ofp.ShowDialog();
解释:
在 WindowsAPICodePack
中,CommonOpenFileDialog
是 CommonFileDialog
class 的子 class。在 CommonFileDialog
中,有一个类型为 IFileDialog
的 nativeDialog
字段(类型 IFileDialog
也不是 public)。您可以使用它来设置按钮的文本。可悲的是,它是私人的。它在仅调用构造函数后也不会初始化(尽管有些方法会初始化它,因此您必须在开始时检查它是否为 null)。 IFileDialog
有一个内部方法 SetOkButtonLabel
。这就是你需要的。