Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

希望可以自定义 Dialog 和 MessageBox 的按钮文字和样式 #422

Open
genment opened this issue Sep 22, 2024 · 7 comments
Open

Comments

@genment
Copy link

genment commented Sep 22, 2024

可自定义内容:

按钮文字、按钮样式、按钮顺序
包括 OverlayDialogDialogMessageBox.Show()MessageBox.ShowOverlay()

应用场景 1(按钮样式、顺序):

比如 YesNo 按钮,目前默认的按钮样式是这样的,看起来很奇怪:

图片

这种情况下,“是”是危险操作,应该在左边,使用红色;而“否”是安全操作,应该在右边,可以使用主题色。

应用场景 2(按钮文字):

默认的按钮文字可能不能满足所有需求(比如国际化、特殊业务场景),如果需要改文字,需要重新定义一个Custom Dialog界面,很麻烦

图片

像这种情况,如果使用 YesNo 按钮,就和上面说的场景1的情况一样了。
如果使用OKCancel,那么这个取消就很迷惑了。
如果可以自定义文字,那么就可以消除这种歧义:[继续执行] [取消任务]

@rabbitism
Copy link
Member

MessageBox的设计完全是为了兼容WPF的API。如果默认按钮的默认文字不符合要求,都应该自己创建CustomDialog来定义

@genment
Copy link
Author

genment commented Sep 22, 2024

感谢回复!那么有没有可能增加一个 MessageBoxEx 来支持这些自定义特性呢?毕竟都是简单的文本内容,每个MessageBox都通过创建 custom dialog 有点杀鸡用牛刀了。

@rabbitism
Copy link
Member

如果只是定义文字的话,只需要在CustomDialog的View中预留Button文字绑定VM的内容,然后每次调用Dialog给VM赋值不同的Button文字就可以了,这样一个CustomDialogView就可以反复使用,不太需要一个单独的API。如果是还要控制颜色和顺序,那就更不可能通过简单的配置来控制了。

@WCKYWCKF
Copy link
Contributor

@genment 比起更改按钮颜色与文本,或许精心设计的Message和Titile更加高效。

@genment
Copy link
Author

genment commented Sep 24, 2024

如果只是定义文字的话,只需要在CustomDialog的View中预留Button文字绑定VM的内容,然后每次调用Dialog给VM赋值不同的Button文字就可以了,这样一个CustomDialogView就可以反复使用,不太需要一个单独的API。如果是还要控制颜色和顺序,那就更不可能通过简单的配置来控制了。

嗯,目前是打算这样做了

@genment 比起更改按钮颜色与文本,或许精心设计的Message和Titile更加高效。

没有专业设计师,只能使用现成的

@dameng324
Copy link
Contributor

遇到了同样的问题,确实如果能够开放自定义按钮内容,将会大大减少这类需求的开发时间。

精心设计一个MessageBox并不容易,如果只为了修改按钮文字而重新编写一个CustomMessageBoxView,确实有些麻烦了。

下面是我花了些时间调的View和ViewModel,希望能够帮助到一些同学。
image

var result = await OverlayDialog.ShowCustomModal<CustomMessageBoxView,CustomMessageBoxViewModel,MessageBoxResult>(
    new CustomMessageBoxViewModel()
    {
        Message = "要退出程序吗?还是隐藏窗口?",
        Button = MessageBoxButton.YesNoCancel,
        YesContent = "退出",
        NoContent = "隐藏",
        CancelContent = "取消",
        Title = "退出",
        Icon = MessageBoxIcon.Question,
    }
);
CustomMessageBoxView.axmal
<UserControl
    MinHeight="100"
    MinWidth="400"
    d:DesignHeight="450"
    d:DesignWidth="800"
    mc:Ignorable="d"
    x:Class="Common.Controls.CustomMessageBoxView"
    x:CompileBindings="True"
    x:DataType="controls:CustomMessageBoxViewModel"
    xmlns="https://github.com/avaloniaui"
    xmlns:controls="clr-namespace:Common.Controls"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:u="https://irihi.tech/ursa"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <StackPanel Margin="30">
        <StackPanel Orientation="Horizontal" Spacing="3">
            <PathIcon Classes.MessageIconNone="{Binding MessageIconNone}"
                      Classes.MessageIconError="{Binding MessageIconError}"
                      Classes.MessageIconQuestion="{Binding MessageIconQuestion}"
                      Classes.MessageIconWarning="{Binding MessageIconWarning}"
                      Classes.MessageIconSuccess="{Binding MessageIconSuccess}"
                      Classes.MessageIconInformation="{Binding MessageIconInformation}"
                      Classes.MessageIconExclamation="{Binding MessageIconExclamation}"
                      Classes.MessageIconAsterisk="{Binding MessageIconAsterisk}"
                      Classes.MessageIconHand="{Binding MessageIconHand}"
                      Classes.MessageIconStop="{Binding MessageIconStop}"
                      Width="24"
                      Height="24"
                      Margin="0,0,10,0"
                      VerticalAlignment="Center"
                      IsHitTestVisible="False">
                <PathIcon.Styles>
                    <Style Selector="PathIcon.MessageIconNone">
                        <Setter Property="IsVisible" Value="False" />
                    </Style>
                    <Style Selector="PathIcon.MessageIconAsterisk, PathIcon.MessageIconInformation">
                        <Setter Property="IsVisible" Value="True" />
                        <Setter Property="Foreground" Value="{DynamicResource SemiBlue6}" />
                        <Setter Property="Data" Value="{DynamicResource DialogInformationIconGlyph}" />
                    </Style>
                    <Style Selector="PathIcon.MessageIconError, PathIcon.MessageIconHand, PathIcon.MessageIconStop">
                        <Setter Property="IsVisible" Value="True" />
                        <Setter Property="Foreground" Value="{DynamicResource SemiRed6}" />
                        <Setter Property="Data" Value="{DynamicResource DialogErrorIconGlyph}" />
                    </Style>
                    <Style Selector="PathIcon.MessageIconExclamation">
                        <Setter Property="IsVisible" Value="True" />
                        <Setter Property="Foreground" Value="{DynamicResource SemiYellow6}" />
                        <Setter Property="Data" Value="{DynamicResource DialogWarningIconGlyph}" />
                    </Style>
                    <Style Selector="PathIcon.MessageIconQuestion">
                        <Setter Property="IsVisible" Value="True" />
                        <Setter Property="Foreground" Value="{DynamicResource SemiBlue6}" />
                        <Setter Property="Data" Value="{DynamicResource DialogQuestionIconGlyph}" />
                    </Style>
                    <Style Selector="PathIcon.MessageIconWarning">
                        <Setter Property="IsVisible" Value="True" />
                        <Setter Property="Foreground" Value="{DynamicResource SemiOrange6}" />
                        <Setter Property="Data" Value="{DynamicResource DialogWarningIconGlyph}" />
                    </Style>
                    <Style Selector="PathIcon.MessageIconSuccess">
                        <Setter Property="IsVisible" Value="True" />
                        <Setter Property="Foreground" Value="{DynamicResource SemiGreen6}" />
                        <Setter Property="Data" Value="{DynamicResource DialogSuccessIconGlyph}" />
                    </Style>
                </PathIcon.Styles>
            </PathIcon>
            <!-- ReSharper disable once Xaml.StyleClassNotFound -->
            <TextBlock Classes="H4" Theme="{DynamicResource TitleTextBlock}"
                       HorizontalAlignment="Left"
                       Text="{Binding Title}" />
        </StackPanel>
        <u:Divider Margin="0,10" Opacity="0.4" />
        <SelectableTextBlock FontSize="15" MinHeight="50" Margin="0,10" Text="{Binding Message}" />
        <StackPanel Orientation="Horizontal"
                    Spacing="15"
                    HorizontalAlignment="Right">
            <!-- ReSharper disable once Xaml.StyleClassNotFound -->
            <Button Content="{Binding OkContent}"
                    Classes="Primary" Theme="{DynamicResource SolidButton}" Command="{Binding OkCommand}" IsVisible="{Binding OkVisible}" />
            <!-- ReSharper disable once Xaml.StyleClassNotFound -->
            <Button Content="{Binding YesContent}"
                    Classes="Primary" Theme="{DynamicResource SolidButton}" Command="{Binding YesCommand}" IsVisible="{Binding YesVisible}" />
            <!-- ReSharper disable once Xaml.StyleClassNotFound -->
            <Button Content="{Binding NoContent}"
                    Classes="Danger" Theme="{DynamicResource SolidButton}" Command="{Binding NoCommand}" IsVisible="{Binding NoVisible}" />
            <!-- ReSharper disable once Xaml.StyleClassNotFound -->
            <Button Content="{Binding CancelContent}"
                    Classes="Tertiary" Theme="{DynamicResource SolidButton}" Command="{Binding CancelCommand}"
                    IsVisible="{Binding CancelVisible}" />
        </StackPanel>
    </StackPanel>
</UserControl>
CustomMessageBoxViewModel.cs
public class CustomMessageBoxViewModel : IDialogContext
{
    public required string Message { get; set; }
    public object? OkContent { get; set; }
    public bool OkVisible => Button is MessageBoxButton.OK or MessageBoxButton.OKCancel;
    public object? CancelContent { get; set; }
    public bool CancelVisible => Button is MessageBoxButton.OKCancel or MessageBoxButton.YesNoCancel;
    public object? YesContent { get; set; }
    public bool YesVisible => Button is MessageBoxButton.YesNo or MessageBoxButton.YesNoCancel;
    public object? NoContent { get; set; }
    public bool NoVisible => Button is MessageBoxButton.YesNo or MessageBoxButton.YesNoCancel;
    public required MessageBoxButton Button { get; set; }
    public required string Title { get; init; }
    public required MessageBoxIcon Icon { get; init; }

    // Asterisk,
    // Error,
    // Exclamation,
    // Hand,
    // Information,
    // None,
    // Question,
    // Stop,
    // Warning,
    // Success,
    public bool MessageIconNone => Icon == MessageBoxIcon.None;
    public bool MessageIconError => Icon == MessageBoxIcon.Error;
    public bool MessageIconWarning => Icon == MessageBoxIcon.Warning;
    public bool MessageIconInformation => Icon == MessageBoxIcon.Information;
    public bool MessageIconQuestion => Icon == MessageBoxIcon.Question;
    public bool MessageIconSuccess => Icon == MessageBoxIcon.Success;
    public bool MessageIconHand => Icon == MessageBoxIcon.Hand;
    public bool MessageIconExclamation => Icon == MessageBoxIcon.Exclamation;
    public bool MessageIconAsterisk => Icon == MessageBoxIcon.Asterisk;
    public bool MessageIconStop => Icon == MessageBoxIcon.Stop;

    public void OkCommand() => RequestClose?.Invoke(this, MessageBoxResult.OK);

    public void CancelCommand() => RequestClose?.Invoke(this, MessageBoxResult.Cancel);

    public void YesCommand() => RequestClose?.Invoke(this, MessageBoxResult.Yes);

    public void NoCommand() => RequestClose?.Invoke(this, MessageBoxResult.No);

    public void Close()
    {
        RequestClose?.Invoke(this, MessageBoxResult.Cancel);
    }

    public event EventHandler<object?>? RequestClose;
}

@genment
Copy link
Author

genment commented Nov 3, 2024

补充一下最近的发现:

原来 Win32 有一个 TaskDialog,包括 dialog 的内容,控件,按钮等等都可以自定义,可定制性非常高。Winforms 在 .net 5 开始也增加了 TaskDialog。我觉得如果 Ursa 可以增加这个控件,会非常棒!

后来又发现 FluentAvalonia 居然已经有类似的控件了:

TaskDialog
image

ContentDialog
ContentDialog

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants