Open
Description
Before API review: see whether we could reuse the classes for TaskDialog
Background and motivation
WPF applications are lacking the ability to customize file dialogs, which has become a common requirement.
Notepad:
Visual Studio:
Office:
This is a proposal for API to enable this functionality in WPF, notably IFileDialogCustomize
.
There is a prototype PR using the proposed API, see #7256.
API Proposal
For class diagram see PR.
Changes to existing:
namespace Microsoft.Win32
{
public abstract partial class CommonItemDialog : CommonDialog
{
protected CommonItemDialog() { }
+ public FileDialogCancelButton CancelButton { get; }
+ public FileDialogCustomControls CustomControls { get; }
public IList<FileDialogCustomPlace> CustomPlaces { get; set; }
public bool DereferenceLinks { get; set; }
public string InitialDirectory { get; set; }
public string FileName { get; set; }
public string[] FileNames { get; }
+ public FileDialogOkButton OkButton { get; }
public bool RestoreDirectory { get; set; }
public string SafeFileName { get; }
public string[] SafeFileNames { get; }
public string Title { get; set; }
public bool ValidateNames { get; set; }
public event CancelEventHandler FileOk { add; remove; }
protected void OnFileOk(CancelEventArgs e) { }
public override void Reset() { }
protected override bool RunDialog(IntPtr hwndOwner);
public override string ToString();
}
}
All new, including the namespace:
namespace Microsoft.Win32.Controls
{
public sealed partial class FileDialogCancelButton
{
public string CustomLabel { get; set; }
}
public sealed partial class FileDialogCheckButton : FileDialogText
{
public FileDialogCheckButton();
public FileDialogCheckButton(string label);
public FileDialogCheckButton(string label, bool isChecked);
public bool IsChecked { get; set; }
public event EventHandler Checked { add; remove; }
public event EventHandler Unchecked { add; remove; }
public override object Clone();
}
public sealed partial class FileDialogComboBox : FileDialogSelectorControl
{
public FileDialogComboBox();
public FileDialogComboBox(params string[] items);
}
public abstract partial class FileDialogControl : FileDialogControlBase, ICloneable
{
protected FileDialogControl();
}
public abstract partial class FileDialogControlBase : ICloneable
{
public FileDialogControlBase();
public int ID { get; }
public bool IsEnabled { get; set; }
public bool IsVisible { get; set; }
public object Tag { get; set; }
public abstract object Clone();
public void HideAndDisable();
public virtual void ShowAndEnable();
}
public partial class FileDialogControlCollection : Collection<FileDialogControl>
{
public FileDialogControlCollection();
public FileDialogControlCollection(params FileDialogControl[] controls);
public FileDialogCheckButton AddCheckButton(string label, bool isChecked = false);
public FileDialogComboBox AddComboBox(params string[] items);
public FileDialogEditBox AddEditBox(string text);
public FileDialogMenu AddMenu(string label, params string[] items);
public FileDialogPushButton AddPushButton(string label);
public FileDialogRadioButtonList AddRadioButtonList(params string[] items);
public FileDialogSeparator AddSeparator();
public FileDialogText AddText(string label);
protected override void ClearItems();
protected override void InsertItem(int index, FileDialogControl item);
protected override void RemoveItem(int index);
protected override void SetItem(int index, FileDialogControl item);
}
public sealed partial class FileDialogControlItem : FileDialogControlBase
{
public FileDialogControlItem();
public FileDialogControlItem(string text);
public string Text { get; set; }
public override object Clone();
}
public partial class FileDialogControlItemCollection : Collection<FileDialogControlItem>
{
internal FileDialogControlItemCollection();
public FileDialogControlItem Add(string itemText);
protected override void ClearItems();
protected override void InsertItem(int index, FileDialogControlItem item);
protected override void RemoveItem(int index);
protected override void SetItem(int index, FileDialogControlItem item);
}
public partial class FileDialogCustomControls : FileDialogControlCollection
{
internal FileDialogCustomControls();
public FileDialogControl Prominent { get; set; }
public FileDialogComboBox AddComboBoxWithLabel(string label, params string[] items);
public FileDialogEditBox AddEditBoxWithLabel(string label, string text);
public FileDialogRadioButtonList AddRadioButtonListWithLabel(string label, params string[] items);
public FileDialogVisualGroup AddVisualGroup(string label, params FileDialogControl[] controls);
}
public sealed partial class FileDialogEditBox : FileDialogControl
{
public FileDialogEditBox();
public FileDialogEditBox(string text);
public string Text { get; set; }
public override object Clone();
}
public partial class FileDialogItemEventArgs : EventArgs
{
public FileDialogItemEventArgs(FileDialogControlItem item);
public FileDialogControlItem Item { get; }
}
public abstract partial class FileDialogItemsControl : FileDialogControl
{
protected FileDialogItemsControl();
protected FileDialogItemsControl(string[] items);
public FileDialogControlItemCollection Items { get; }
public sealed override object Clone();
}
public sealed partial class FileDialogMenu : FileDialogItemsControl
{
public FileDialogMenu();
public FileDialogMenu(string label, params string[] items);
public string Label { get; set; }
public event EventHandler Activating { add; remove; }
public event EventHandler<FileDialogItemEventArgs> ItemSelected { add; remove; }
}
public sealed partial class FileDialogOkButton
{
public string CustomLabel { get; set; }
public FileDialogControlItemCollection Items { get; }
public bool RequiresInteraction { get; set; }
public int SelectedIndex { get; }
public FileDialogControlItem SelectedItem { get; }
public event EventHandler Activating { add; remove; }
}
public sealed partial class FileDialogPushButton : FileDialogText
{
public FileDialogPushButton();
public FileDialogPushButton(string label);
public event EventHandler Click { add; remove; }
public override object Clone();
}
public sealed partial class FileDialogRadioButtonList : FileDialogSelectorControl
{
public FileDialogRadioButtonList()
public FileDialogRadioButtonList(params string[] items)
}
public abstract partial class FileDialogSelectorControl : FileDialogItemsControl
{
protected FileDialogSelectorControl(params string[] items);
public int SelectedIndex { get; set; }
public FileDialogControlItem SelectedItem { get; set; }
public event EventHandler<FileDialogItemEventArgs> ItemSelected { add; remove; }
}
public sealed partial class FileDialogSeparator : FileDialogControl
{
public FileDialogSeparator();
public override object Clone();
}
public partial class FileDialogText : FileDialogControl
{
public FileDialogText();
public FileDialogText(string label);
public string Label { get; set; }
public override object Clone();
}
public sealed partial class FileDialogVisualGroup : FileDialogText
{
public FileDialogVisualGroup(string label);
public FileDialogVisualGroup(string label, params FileDialogControl[] controls);
public FileDialogControlCollection Controls { get; }
public void Add(FileDialogControl control);
public override object Clone();
}
}
API Usage
var dialog = new SaveFileDialog();
dialog.Filter = "All files (*.*)|*.*";
var radioGroup = new FileDialogVisualGroup("RadioButtonList");
radioGroup.Add(new FileDialogRadioButtonList("_radio 1", "r_adio 2", "ra_dio 3"));
dialog.CustomControls.Add(radioGroup);
var checkGroup = new FileDialogVisualGroup("CheckButtons");
checkGroup.Add(new FileDialogCheckButton("_check 1"));
checkGroup.Add(new FileDialogCheckButton("c_heck 2", false));
checkGroup.Add(new FileDialogCheckButton("chec_k 3", true));
dialog.CustomControls.Add(checkGroup);
var menuGroup = new FileDialogVisualGroup("Menus and separator");
menuGroup.Add(new FileDialogMenu("_menu 1", "item _1", "item _2"));
menuGroup.Add(new FileDialogSeparator());
menuGroup.Add(new FileDialogMenu("m_enu 2", "item"));
dialog.CustomControls.Add(menuGroup);
var comboGroup = new FileDialogVisualGroup("ComboBoxes");
comboGroup.Add(new FileDialogComboBox("item _1", "item &2", "item 3"));
comboGroup.Add(new FileDialogComboBox("item _1", "item &2", "item 3") { SelectedIndex = 1 });
dialog.CustomControls.Add(comboGroup);
var textGroup = new FileDialogVisualGroup("Text and EditBo_x");
textGroup.Add(new FileDialogText("Generic _label"));
textGroup.Add(new FileDialogEditBox("a text box 😊"));
dialog.CustomControls.Add(textGroup);
var pushButton = new FileDialogPushButton("A button not in a _group");
pushButton.Click += delegate { MessageBox.Show("Clicked!"); };
dialog.CustomControls.Add(pushButton);
var prominentGroup = new FileDialogVisualGroup("Pro_minent control", new FileDialogComboBox());
dialog.CustomControls.Add(prominentGroup);
dialog.CustomControls.Prominent = prominentGroup;
dialog.OkButton.Items.Add("_Add");
dialog.OkButton.Items.Add("Add a_ll");
dialog.CancelButton.CustomLabel = "_Done";
dialog.ShowDialog();
Alternative Designs
No response
Risks
Low from the API surface perspective, this is all new functionality not changing the existing behavior.
Metadata
Metadata
Assignees
Labels
No labels