|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
namespace System.Windows.Forms;
/// <summary>
/// Represents the footnote area of a task dialog.
/// </summary>
public sealed class TaskDialogFootnote : TaskDialogControl
{
private string? _text;
private TaskDialogIcon? _icon;
private bool _boundIconIsFromHandle;
private bool _updateTextOnInitialization;
/// <summary>
/// Initializes a new instance of the <see cref="TaskDialogFootnote"/> class.
/// </summary>
public TaskDialogFootnote()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="TaskDialogFootnote"/> class
/// using the given <paramref name="text"/>.
/// </summary>
/// <param name="text">The text to be displayed in the dialog's footnote area.</param>
public TaskDialogFootnote(string? text)
: this()
{
_text = text;
}
public static implicit operator TaskDialogFootnote(string footnoteText)
=> new(footnoteText);
/// <summary>
/// Gets or sets the text to be displayed in the dialog's footnote area.
/// </summary>
/// <value>
/// The text to be displayed in the dialog's footnote area. The default value is <see langword="null"/>.
/// </value>
/// <remarks>
/// <para>
/// This control will only be shown if this property is not <see langword="null"/> or an empty string.
/// </para>
/// <para>
/// This property can be set while the dialog is shown.
/// </para>
/// </remarks>
/// <exception cref="InvalidOperationException">
/// The property is set on a footnote instance that is currently bound to a task dialog, but it's not visible as its initial
/// <see cref="Text"/> property value was <see langword="null"/> or an empty string.
/// - or -
/// The property is set on a footnote instance that is currently bound to a task dialog, but the dialog
/// has just started navigating to a different page.
/// </exception>
public string? Text
{
get => _text;
set
{
DenyIfBoundAndNotCreated();
if (BoundPage is not null)
{
// If we are bound but waiting for initialization (e.g. immediately after
// starting a navigation), we buffer the change until we apply the
// initialization (when navigation is finished).
if (BoundPage.WaitingForInitialization)
{
_updateTextOnInitialization = true;
}
else
{
BoundPage.BoundDialog!.UpdateTextElement(
TASKDIALOG_ELEMENTS.TDE_FOOTER, value);
}
}
_text = value;
}
}
/// <summary>
/// Gets or sets the footnote icon.
/// </summary>
/// <remarks>
/// <para>
/// This property can be set while the dialog is shown (but in that case, it
/// cannot be switched between instances created from an
/// <see cref="Drawing.Icon"/> (or from a handle pointer)
/// and standard icon instances).
/// </para>
/// </remarks>
/// <exception cref="InvalidOperationException">
/// The property is set on a footnote instance that is currently bound to a task dialog, but it's not visible as its initial
/// <see cref="Text"/> property value was <see langword="null"/> or an empty string.
/// - or -
/// The property is set and the task dialog has started navigating to a new page containing this footnote instance, but the
/// <see cref="TaskDialogPage.Created"/> event has not been raised yet.
/// - or -
/// The property is set on a footnote instance that is currently bound to a task dialog, but the dialog
/// has just started navigating to a different page.
/// </exception>
public unsafe TaskDialogIcon? Icon
{
get => _icon;
set
{
DenyIfBoundAndNotCreated();
// See comment in TaskDialogPage.Icon for why we don't allow to buffer changes
// while waiting for the initialization.
DenyIfWaitingForInitialization();
if (BoundPage is not null)
{
(TASKDIALOGCONFIG._Anonymous2_e__Union icon, bool? iconIsFromHandle) =
TaskDialogPage.GetFooterIconValue(value);
// The native task dialog icon cannot be updated from a handle
// type to a non-handle type and vice versa, so we need to throw
// in such a case.
if (iconIsFromHandle is not null && iconIsFromHandle != _boundIconIsFromHandle)
{
throw new InvalidOperationException(SR.TaskDialogCannotUpdateIconType);
}
BoundPage.BoundDialog!.UpdateIconElement(
TASKDIALOG_ICON_ELEMENTS.TDIE_ICON_FOOTER,
_boundIconIsFromHandle ? icon.hFooterIcon : (IntPtr)(char*)icon.pszFooterIcon);
}
_icon = value;
}
}
internal override bool IsCreatable => base.IsCreatable && !TaskDialogPage.IsNativeStringNullOrEmpty(_text);
/// <summary>
/// Returns a string that represents the current <see cref="TaskDialogFootnote"/> control.
/// </summary>
/// <returns>A string that contains the control text.</returns>
public override string ToString() => _text ?? base.ToString() ?? string.Empty;
internal TASKDIALOG_FLAGS Bind(TaskDialogPage page, out TASKDIALOGCONFIG._Anonymous2_e__Union icon)
{
TASKDIALOG_FLAGS result = Bind(page);
icon = TaskDialogPage.GetFooterIconValue(_icon).iconUnion;
return result;
}
private protected override TASKDIALOG_FLAGS BindCore()
{
TASKDIALOG_FLAGS flags = base.BindCore();
_updateTextOnInitialization = false;
_boundIconIsFromHandle = TaskDialogPage.GetFooterIconValue(_icon).iconIsFromHandle ?? false;
if (_boundIconIsFromHandle)
{
flags |= TASKDIALOG_FLAGS.TDF_USE_HICON_FOOTER;
}
return flags;
}
private protected override void ApplyInitializationCore()
{
base.ApplyInitializationCore();
if (_updateTextOnInitialization)
{
Text = _text;
_updateTextOnInitialization = false;
}
}
private protected override void UnbindCore()
{
_boundIconIsFromHandle = false;
base.UnbindCore();
}
}
|