using MahApps.Metro.Controls; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Shapes; namespace LunarSF.SHomeWorkshop.LunarMarkdownEditor { /// <summary> /// InputBox.xaml 的交互逻辑 /// </summary> public partial class InputBox : MetroWindow { /// <summary> /// [私有构造方法]用以创建一个输入窗口。 /// 此类只用静态方法调用,所以不需要公有的构造方法。 /// 调用方式:InputBox.Show(...); /// </summary> private InputBox() { InitializeComponent(); } /// <summary> /// 显示一个输入框,并获取输入的数据。 /// </summary> /// <param name="title">输入框标题。</param> /// <param name="prompt">输入框中的提示文本。</param> /// <param name="defaultValue">输入框的默认文本。</param> /// <param name="isFilePath">是否应输入文件名。这会影响数据校验的结果。</param> /// <param name="prompt2">第二提示文本。</param> /// <param name="isPassword">是否打算输入密码。如果为真,输入时文本透明(不可见)。</param> public static string Show(string title, string prompt, string defaultValue, bool isFilePath, string prompt2 = null, bool isPassword = false) { InputBox ibx = new InputBox(); ibx.Owner = App.Current.MainWindow; ibx.WindowStartupLocation = WindowStartupLocation.CenterOwner; ibx.Icon = ibx.Owner.Icon; ibx.Title = title; ibx.tbxPrompt.Text = prompt; ibx.tbxInput.Text = defaultValue; ibx.IsPassword = isPassword; if (string.IsNullOrEmpty(prompt2)) { ibx.tbxPrompt2.Visibility = Visibility.Collapsed; } else { ibx.tbxPrompt2.Visibility = Visibility.Visible; ibx.tbxPrompt2.Text = prompt2; } ibx.tbxInput.SelectAll(); //已经可以支持直接取拼音首字母替换中文字符,不需要这个了。 //if (isFilePath) //{ // Globals.SwitchInputMethod(Globals.MainWindow.ShowTitleInWorkspaceManager); //} if (isPassword) { //ibx.tbxInput.SelectionBrush = //ibx.tbxInput.CaretBrush = ibx.tbxInput.Foreground = Brushes.Transparent; Globals.SwitchInputMethod(Globals.MainWindow.ShowTitleInWorkspaceManager); } if (ibx.ShowDialog() == true) { if (isFilePath && isPassword == false) { var result = ibx.tbxInput.Text.Replace(" ", "-"); if (result.StartsWith("_")) result = result.Substring(1); result = result.Replace("_", "-"); return result; } else { return ibx.tbxInput.Text;//原文输出 } } return null; } /// <summary> /// 密码应原文输出。 /// </summary> public bool IsPassword { get; set; } = false; /// <summary> /// 完成输入。 /// </summary> private void btnOK_Click(object sender, RoutedEventArgs e) { if (IsFilePath) { if (ValidateFilePath(this.tbxInput.Text, true) == false) { if (ValidateFilePath(this.tbxInput.Text, false)) { var result = LMessageBox.Show(" 建议使用英文字母、数字来命名,并且最好以英文字母开头(某些网络设备对数字开头的文件名支持欠佳)。\r\n" + " 文件名(或文件夹名)使用特殊字符或汉字可能导致编译出的 CHM 文档中某些链接无效。" + "只有一定范围的汉字会被转换为拼音首字母,而其它字符不会转换,所以仍然可能出错。\r\n\r\n" + " 你确定要这样做吗?", Globals.AppName, MessageBoxButton.YesNo, MessageBoxImage.Warning, "NPA_UseSpecialCharForFileName"); // NPA_ means No Prompt Again. if (result != MessageBoxResult.Yes) return; else { this.DialogResult = true; this.Close(); return; } } else { //var forbidonChars1 = "\\ / : * \" < > |"; //var forbidonChars2 = @"+ "" # % & ( ) + , : ; < = > ? @ |"; //tbxPrompt2.Text = $" 文件名只能使用字母、数字、下划线(_)字符。\r\n 下列字符为 Windows 文件系统禁用字符:\r\n {forbidonChars1}\r\n 下列特殊字符会造成编译后的 CHM 文件中出现路径错误:\r\n {forbidonChars2}";// "文件名中不能包含:\\/:*\"<>|"; tbxPrompt2.Text = " 文件名只能使用字母、数字、下划线(_)字符,且应以字母开头(不能以下划线字符[_]和数字字符开头。\r\n" + " ※因为某些网络设备(或软件)对一些特殊字符支持很差。"; tbxPrompt2.Visibility = Visibility.Visible; return; } } } this.DialogResult = true; this.Close(); } private bool isFilePath = true; /// <summary> /// 指明输入的文本是否应通过文件名规则校验。 /// </summary> public bool IsFilePath { get { return isFilePath; } set { isFilePath = value; } } /// <summary> /// 与“MainWindow.cs”下的同名方法不同:禁止出现冒号和路径分割符。 /// 只允许字母、数字、下划线、句点,且不能以下划线开头。 /// </summary> /// <param name="text">文件短名。</param> /// <returns></returns> public static bool ValidateFilePath(string text, bool highLevel) { if (string.IsNullOrEmpty(text)) return false; if (text.StartsWith("_")) return false; if (highLevel) { foreach (char c in text) { if (c >= 'a' && c <= 'z') continue; if (c >= 'A' && c <= 'Z') continue; if (c >= '0' && c <= '9') continue; if (c == '_' || c == '.' || c == ' ') continue; return false; } return true; } if (text.Contains("/") || text.Contains("\\") || text.Contains(":") || text.Contains(":") || //已知全角冒号也会导致链接失效 text.Contains("*") || text.Contains("\"") || text.Contains("<") || text.Contains(">") || text.Contains("|") || text.Contains("[") || //方括号会导致图像链接文本切分时识别出错。 text.Contains("]")) //方括号会导致图像链接文本切分时识别出错。 { return false; } foreach (char c in text) { //全角标点均可用,半角标点不允许前列特殊字符。另, //半角波形符用于资源文件夹,不可用。 //下划线用于目录元文件,不可用。 //反引号符备用,不可用。 //右面这些字符是 URL 要转义的,所以不能使用:+"#%&()+,/:;<=>?@\| if (@"+""#%&()+,/:;<=>?@\|".Contains(c)) return false; if ("!@$^-{}',.~·@#¥%…&*()【】{}|;‘’“”,。《〈〉》?".Contains(c)) continue; //已知全角冒号也会导致 Markdown 文件转换成 Html 文件后图像链接失效。 //全角字符就算是特殊符号也是可以的 //全角小写字母 if (c == '、') continue; if (c >= 'a' && c <= 'z') continue; //全角大写字母 if (c >= 'A' && c <= 'Z') continue; //!"#$%&'()*+,-./ if (c >= '!' && c <= '/') continue; //全角数字 if (c >= '0' && c <= '9') continue; //:;<=>?@ if (c >= ':' && c <= '@') continue; //[\]^_` if (c >= '[' && c <= '`') continue; //{|}~ if (c >= '{' && c <= '~') continue; //¢£¬ ̄¦¥ if (c >= '¢' && c <= '¥') continue; //全角字符就算是特殊符号也是可以的 //全角问号'?',就是>0x9fbb的。 if (c > 0x9fbb) { if (c == '§') continue; if (c == '☆') continue; if (c == '★') continue; if (c == '○') continue; if (c == '●') continue; if (c == '◎') continue; if (c == '◇') continue; if (c == '◆') continue; if (c == '□') continue; if (c == '■') continue; if (c == '△') continue; if (c == '▲') continue; if (c == '※') continue; if (c == '〓') continue; if (c == '#') continue; if (c == '&') continue; if (c == '@') continue; if (c == '_') continue; if (c == ' ̄') continue; return false; } if (c < 0x4e00) { if (c >= '0' && c <= '9') continue; if (c == '_') continue; if (c == '+') continue; if (c == '-') continue; if (c == '.') continue;//后缀名需要 if (c == '=') continue; if (c == ' ') continue; if (c == '(') continue; if (c == ')') continue; if (c == ')') continue; if (c == '(') continue; if (c >= '⑴' && c <= '⒇') continue; if (c >= '①' && c <= '⑩') continue; if (c >= '⒈' && c <= '⒛') continue; if (c >= 'A' && c <= 'Z') continue; if (c >= 'a' && c <= 'z') continue; return false; } } return true; } /// <summary> /// 放弃输入,关闭窗口。 /// </summary> private void btnCancel_Click(object sender, RoutedEventArgs e) { //if (IsFilePath) //{ // if (ValidateFilePath() == false) // { // tbxPrompt2.Text = "文件名中不能包含:\\/:*\"<>|"; // return; // } //} this.DialogResult = false; this.Close(); } /// <summary> /// 回车键完成输入;Esc键放弃输入。 /// </summary> private void tbxInput_KeyDown(object sender, KeyEventArgs e) { if (e.Key == Key.Enter) { btnOK_Click(sender, e); } else if (e.Key == Key.Escape) { btnCancel_Click(sender, e); } } /// <summary> /// 窗口载入时自动对焦,便于立即开始输入。 /// </summary> private void Window_Loaded(object sender, RoutedEventArgs e) { tbxInput.Focus(); } } }