Dynamische Dialoggröße wie bei MessageBox

  • C#
  • .NET (FX) 1.0–2.0

Es gibt 6 Antworten in diesem Thema. Der letzte Beitrag () ist von TRiViUM.

    Dynamische Dialoggröße wie bei MessageBox

    Guten Morgen liebe Leute,

    ich habe vor, eine eigene Messagebox zu programmieren.
    Mit einem kleine Trick habe ich den Dialog auch dazu gebracht, dynamisch mit dem anzuzeigenden Text mitzuwachsen.
    Allerdings gibt es dadurch noch ein unschönes Verhalten.

    Aufbau kurz erklärt:
    Eine Form beinhaltet ein Label, was den Text anzeigen soll.
    Das Label selbst hat AutoSize=True, MaximumSize=480;800 und AutoEllipsis=True.
    Damit wird erreicht, dass das Label nur max. 480 Pixel breit und 800 Pixel hoch werden kann.
    Dann wird der Text gesetzt, das Label ändert darauf hin seine Größe und ich muss nur noch die Dialoggröße anpassen.

    Wenn ich jetzt einen Text ohne Zeilenumbrüche schreibe, der für das Label (in max. Größe 480x800) zu lang ist, werden die letzten 3 Zeichen durch ... ersetzt (AutoEllipsis), soweit gut.
    Wenn ich jedoch nach jedem Buchstaben Zeilenumbrüche mache, sodass zwar nicht die max. Breite, jedoch die max. Höhe ausgenutzt wird, erscheinen keine ... und man denkt, der Text wäre zu Ende.

    Ich probiere mich momentan auch noch daran, den Text selber umzubrechen.
    Allerdings erscheint mir das gar nicht mal so einfach, weshalb ich mich gefragt habe, ob das Framework dafür eine Lösung parat hat ?

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „TRiViUM“ ()

    Ich hab mir vor ner Weile auch ne eigene MessageBox gebastelt. Jetzt kann ich auch mehrere Buttons verwenden, je mit eigener Beschriftung. Das Problem mit dem zu langen Text habe ich so gelöst, dass ich ein Panel verwende. Wenn der Text von der Höhe zu lang ist, wird ein Scrollbalken angezeigt. Dementsprechend wird die MessageBox nur eine gewissen Maximalhöhe erreichen. Und wenn der Text mehr braucht, kann man scrollen. Und wenn der Text zu lang wird (Zeichenzahl), wird er gekürzt und angehängt.
    Die Textgrößenberechnung und der Umgang mit einem & im Text waren einige kleinere Hürden.
    Bilder
    • MsgBox1.png

      3,81 kB, 514×166, 63 mal angesehen
    • MsgBox2.png

      4,89 kB, 245×539, 60 mal angesehen
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „VaporiZed“ ()

    Über ein Panel hatte ich auch schon nachgedacht. Allerdings fand ich das mit dem Scrollbalken nicht so schön und wollte doch eher an der original-Messagebox bleiben.
    Wobei ich vermutlich doch dazu tendiere, wenn es wirklich nicht anders geht...

    Hier mal mein aktueller Ansatz:
    Spoiler anzeigen

    C#-Quellcode

    1. using System;
    2. using System.Drawing;
    3. using System.Reflection;
    4. using System.Windows.Forms;
    5. using System.Collections.Generic;
    6. using System.Runtime.InteropServices;
    7. namespace EDTest_Func.Ui
    8. {
    9. public partial class UserMessageBox : Form
    10. {
    11. #region designer
    12. /// <summary>
    13. /// Required designer variable.
    14. /// </summary>
    15. private System.ComponentModel.IContainer components = null;
    16. /// <summary>
    17. /// Clean up any resources being used.
    18. /// </summary>
    19. /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
    20. protected override void Dispose(bool disposing)
    21. {
    22. if (disposing && ( components != null ))
    23. {
    24. components.Dispose();
    25. }
    26. base.Dispose( disposing );
    27. }
    28. #region Windows Form Designer generated code
    29. /// <summary>
    30. /// Required method for Designer support - do not modify
    31. /// the contents of this method with the code editor.
    32. /// </summary>
    33. private void InitializeComponent()
    34. {
    35. this.lblContent = new System.Windows.Forms.Label();
    36. this.pbIcon = new System.Windows.Forms.PictureBox();
    37. this.pDialog = new System.Windows.Forms.Panel();
    38. this.panel1 = new System.Windows.Forms.Panel();
    39. ((System.ComponentModel.ISupportInitialize)(this.pbIcon)).BeginInit();
    40. this.pDialog.SuspendLayout();
    41. this.SuspendLayout();
    42. //
    43. // lblContent
    44. //
    45. this.lblContent.AutoEllipsis = true;
    46. this.lblContent.AutoSize = true;
    47. this.lblContent.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
    48. this.lblContent.Location = new System.Drawing.Point(68, 24);
    49. this.lblContent.Margin = new System.Windows.Forms.Padding(10, 0, 3, 0);
    50. this.lblContent.MaximumSize = new System.Drawing.Size(0, 800);
    51. this.lblContent.Name = "lblContent";
    52. this.lblContent.Size = new System.Drawing.Size(73, 20);
    53. this.lblContent.TabIndex = 22;
    54. this.lblContent.Text = "Content";
    55. //
    56. // pbIcon
    57. //
    58. this.pbIcon.Location = new System.Drawing.Point(23, 24);
    59. this.pbIcon.Name = "pbIcon";
    60. this.pbIcon.Size = new System.Drawing.Size(32, 32);
    61. this.pbIcon.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
    62. this.pbIcon.TabIndex = 23;
    63. this.pbIcon.TabStop = false;
    64. //
    65. // pDialog
    66. //
    67. this.pDialog.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(240)))), ((int)(((byte)(240)))), ((int)(((byte)(240)))));
    68. this.pDialog.Controls.Add(this.panel1);
    69. this.pDialog.Dock = System.Windows.Forms.DockStyle.Bottom;
    70. this.pDialog.Location = new System.Drawing.Point(0, 107);
    71. this.pDialog.Name = "pDialog";
    72. this.pDialog.Size = new System.Drawing.Size(528, 73);
    73. this.pDialog.TabIndex = 25;
    74. //
    75. // panel1
    76. //
    77. this.panel1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(223)))), ((int)(((byte)(223)))), ((int)(((byte)(223)))));
    78. this.panel1.Dock = System.Windows.Forms.DockStyle.Top;
    79. this.panel1.Location = new System.Drawing.Point(0, 0);
    80. this.panel1.Name = "panel1";
    81. this.panel1.Size = new System.Drawing.Size(528, 1);
    82. this.panel1.TabIndex = 0;
    83. //
    84. // UserMessageBox
    85. //
    86. this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
    87. this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
    88. this.BackColor = System.Drawing.Color.White;
    89. this.ClientSize = new System.Drawing.Size(528, 180);
    90. this.Controls.Add(this.pDialog);
    91. this.Controls.Add(this.pbIcon);
    92. this.Controls.Add(this.lblContent);
    93. this.DoubleBuffered = true;
    94. this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
    95. this.MaximizeBox = false;
    96. this.MinimizeBox = false;
    97. this.Name = "UserMessageBox";
    98. this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
    99. this.Text = "UserMessageBox";
    100. this.Shown += new System.EventHandler(this.UserMessageBox_Shown);
    101. ((System.ComponentModel.ISupportInitialize)(this.pbIcon)).EndInit();
    102. this.pDialog.ResumeLayout(false);
    103. this.ResumeLayout(false);
    104. this.PerformLayout();
    105. }
    106. #endregion
    107. private System.Windows.Forms.Label lblContent;
    108. private System.Windows.Forms.PictureBox pbIcon;
    109. private System.Windows.Forms.Panel pDialog;
    110. private System.Windows.Forms.Panel panel1;
    111. #endregion
    112. #region dll imports
    113. [DllImport( "user32.dll" )]
    114. private static extern void SetForegroundWindow(IntPtr hWnd);
    115. #endregion
    116. #region constructor
    117. public UserMessageBox()
    118. {
    119. InitializeComponent();
    120. Icon = Icon.ExtractAssociatedIcon( Assembly.GetEntryAssembly().Location );
    121. buttonList = new List<Button>();
    122. TopMost = true;
    123. }
    124. #endregion
    125. #region constants
    126. private static readonly Color Button_Blue = Color.FromArgb( 41, 128, 185 );
    127. private static readonly Color Button_Red = Color.FromArgb( 231, 76, 60 );
    128. private static readonly Color Button_Green = Color.FromArgb( 27, 174, 88 );
    129. //private static readonly Color Button_Orange = Color.FromArgb( 255, 128, 0 );
    130. private static readonly Color Button_OrangeYellow = Color.FromArgb( 255, 175, 0 );
    131. private static readonly Font ButtonFont = new Font( "Segoe UI", 14.25f, FontStyle.Bold );
    132. private static readonly int MaxTextWidth = 366;
    133. #endregion
    134. #region variables
    135. private readonly List<Button> buttonList;
    136. #endregion
    137. #region properties
    138. private string title;
    139. internal string Title
    140. {
    141. get { return title; }
    142. set
    143. {
    144. title = value;
    145. Text = title;
    146. }
    147. }
    148. private string content;
    149. internal string Content
    150. {
    151. get { return content; }
    152. set
    153. {
    154. content = value;
    155. lblContent.Text = content;
    156. }
    157. }
    158. internal MessageBoxButtons Buttons { get; set; }
    159. #endregion
    160. #region methods
    161. private void AddButton(string text, DialogResult dialogResult)
    162. {
    163. //prepare button
    164. Button btn = new Button();
    165. btn.Size = new Size( 150, 50 );
    166. btn.FlatStyle = FlatStyle.Flat;
    167. btn.FlatAppearance.BorderSize = 0;
    168. btn.Font = ButtonFont;
    169. btn.DialogResult = dialogResult;
    170. btn.Text = text;
    171. btn.ForeColor = Color.White;
    172. btn.Margin = new Padding( 11 );
    173. //set dialog result for the button
    174. if ( dialogResult == DialogResult.OK ||
    175. dialogResult == DialogResult.Retry) btn.BackColor = Button_Blue;
    176. else if( dialogResult == DialogResult.Yes ) btn.BackColor = Button_Green;
    177. else if( dialogResult == DialogResult.Abort ||
    178. dialogResult == DialogResult.Cancel ||
    179. dialogResult == DialogResult.No) btn.BackColor = Button_Red;
    180. else if (dialogResult == DialogResult.Ignore) btn.BackColor = Button_OrangeYellow;
    181. //calculate location
    182. int x = pDialog.Width - btn.Width - btn.Margin.Right - ( buttonList.Count * (btn.Width + btn.Margin.Right));
    183. int y = pDialog.Height - btn.Height - btn.Margin.Bottom;
    184. btn.Location = new Point(x, y);
    185. //add control
    186. pDialog.Controls.Add( btn );
    187. //add button to list (for multiple buttons)
    188. buttonList.Add( btn );
    189. }
    190. private void AddButtons(MessageBoxButtons buttons)
    191. {
    192. // Original alingment
    193. // Abort Retry Ignore
    194. // OK
    195. // OK Cancel
    196. // Retry Cancel
    197. // Yes No
    198. // Yes No Cancel
    199. if (buttons == MessageBoxButtons.AbortRetryIgnore )
    200. {
    201. AddButton( "Ignorieren", DialogResult.Ignore );
    202. AddButton( "Wiederholen", DialogResult.Retry );
    203. AddButton( "Abbrechen", DialogResult.Abort );
    204. }
    205. else if (buttons == MessageBoxButtons.OK )
    206. AddButton( "OK", DialogResult.OK );
    207. else if (buttons == MessageBoxButtons.OKCancel )
    208. {
    209. AddButton( "Abbrechen", DialogResult.Cancel );
    210. AddButton( "OK", DialogResult.OK );
    211. }
    212. else if (buttons == MessageBoxButtons.RetryCancel )
    213. {
    214. AddButton( "Abbrechen", DialogResult.Cancel );
    215. AddButton( "Wiederholen", DialogResult.Retry );
    216. }
    217. else if (buttons == MessageBoxButtons.YesNo )
    218. {
    219. AddButton( "Nein", DialogResult.No );
    220. AddButton( "Ja", DialogResult.Yes );
    221. }
    222. else if (buttons == MessageBoxButtons.YesNoCancel )
    223. {
    224. AddButton( "Abbrechen", DialogResult.Cancel );
    225. AddButton( "Nein", DialogResult.No );
    226. AddButton( "Ja", DialogResult.Yes );
    227. }
    228. }
    229. private void SetIcon(MessageBoxIcon icon)
    230. {
    231. if (icon == MessageBoxIcon.None)
    232. {
    233. pbIcon.Visible = false;
    234. lblContent.Location = new Point( 23, lblContent.Location.Y );
    235. lblContent.MaximumSize = new Size( 480, 800 );
    236. }
    237. else
    238. {
    239. lblContent.Location = new Point( 68, lblContent.Location.Y );
    240. lblContent.MaximumSize = new Size( 425, 800 );
    241. if (icon == MessageBoxIcon.Information || icon == MessageBoxIcon.Asterisk)
    242. pbIcon.Image = SystemIcons.Information.ToBitmap();
    243. else if (icon == MessageBoxIcon.Error || icon == MessageBoxIcon.Stop || icon == MessageBoxIcon.Hand)
    244. pbIcon.Image = SystemIcons.Error.ToBitmap();
    245. else if (icon == MessageBoxIcon.Warning || icon == MessageBoxIcon.Exclamation)
    246. pbIcon.Image = SystemIcons.Warning.ToBitmap();
    247. else if (icon == MessageBoxIcon.Question)
    248. pbIcon.Image = SystemIcons.Question.ToBitmap();
    249. }
    250. }
    251. private void SetDefaultButton( MessageBoxDefaultButton defaultButton)
    252. {
    253. if (defaultButton == MessageBoxDefaultButton.Button1)
    254. {
    255. ActiveControl = buttonList[0];
    256. }
    257. else if (defaultButton == MessageBoxDefaultButton.Button2)
    258. {
    259. if( buttonList.Count >= 2)
    260. ActiveControl = buttonList[1];
    261. else
    262. ActiveControl = buttonList[0];
    263. }
    264. else if (defaultButton == MessageBoxDefaultButton.Button3)
    265. {
    266. if (buttonList.Count >= 3)
    267. ActiveControl = buttonList[2];
    268. else
    269. ActiveControl = buttonList[0];
    270. }
    271. }
    272. #endregion
    273. #region functions
    274. private DialogResult display()
    275. {
    276. Height = lblContent.Height + pDialog.Height + 100;
    277. return ShowDialog();
    278. }
    279. private static DialogResult ShowTest(string text)
    280. {
    281. using (UserMessageBox dialog = new UserMessageBox())
    282. {
    283. #region calculate text size
    284. string[] contentSegments = text.Split( new string[] { Environment.NewLine }, StringSplitOptions.None );
    285. Size textSize = TextRenderer.MeasureText( text, ButtonFont );
    286. string displayContent = "";
    287. if (textSize.Width > MaxTextWidth)
    288. {
    289. }
    290. #endregion
    291. dialog.Title = "";
    292. dialog.Content = text;
    293. dialog.AddButtons( MessageBoxButtons.OK );
    294. dialog.SetIcon( MessageBoxIcon.None );
    295. return dialog.display();
    296. }
    297. }
    298. public static DialogResult Show(string text)
    299. {
    300. using (UserMessageBox dialog = new UserMessageBox())
    301. {
    302. dialog.Title = "";
    303. dialog.Content = text;
    304. dialog.AddButtons( MessageBoxButtons.OK );
    305. dialog.SetIcon( MessageBoxIcon.None );
    306. return dialog.display();
    307. }
    308. }
    309. public static DialogResult Show(string text, string title)
    310. {
    311. using (UserMessageBox dialog = new UserMessageBox())
    312. {
    313. dialog.Title = title;
    314. dialog.Content = text;
    315. dialog.AddButtons( MessageBoxButtons.OK );
    316. dialog.SetIcon( MessageBoxIcon.None );
    317. return dialog.display();
    318. }
    319. }
    320. public static DialogResult Show(string text, string title, MessageBoxButtons buttons)
    321. {
    322. using (UserMessageBox dialog = new UserMessageBox())
    323. {
    324. dialog.Title = title;
    325. dialog.Content = text;
    326. dialog.AddButtons( buttons );
    327. dialog.SetIcon( MessageBoxIcon.None );
    328. return dialog.display();
    329. }
    330. }
    331. public static DialogResult Show(string text, string title, MessageBoxButtons buttons, MessageBoxIcon icon)
    332. {
    333. using (UserMessageBox dialog = new UserMessageBox())
    334. {
    335. dialog.Title = title;
    336. dialog.Content = text;
    337. dialog.SetIcon( icon );
    338. dialog.AddButtons( buttons );
    339. return dialog.display();
    340. }
    341. }
    342. public static DialogResult Show(string text, string title, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton)
    343. {
    344. using (UserMessageBox dialog = new UserMessageBox())
    345. {
    346. dialog.Title = title;
    347. dialog.Content = text;
    348. dialog.SetIcon( icon );
    349. dialog.AddButtons( buttons );
    350. dialog.SetDefaultButton( defaultButton );
    351. return dialog.display();
    352. }
    353. }
    354. #endregion
    355. #region callbacks
    356. private void UserMessageBox_Shown(object sender, System.EventArgs e)
    357. {
    358. BringToFront();
    359. Activate();
    360. SetForegroundWindow( Handle );
    361. }
    362. #endregion
    363. }
    364. }

    Wobei die Funktion ShowTest nicht ausprogrammiert wurde, das war der Anfang für das manuelle Umbrechen des Strings...

    Achja:
    Ich hatte noch vergessen zu erwähnen, dass das ganze für ne Touch-Eingabe optimiert ist, daher auch die größeren Buttons.
    Bei so einem kleinen Scrollbalken wird es etwas schwierig, wobei man den bestimmt auch noch irgendwie groß bekommen würde denke ich...

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „TRiViUM“ ()

    Die MaxHöhe passt aber noch nicht ganz. Das sind mehr als die eingestellten 800 px.
    Bilder
    • MsgBox3.png

      17,11 kB, 536×968, 61 mal angesehen
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Ah, ok.
    Bisher wird mein 1002-Zeilentext abgeschnitten. Was ist Dein Plan dafür, damit man den Rest sieht?
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Ich musste gerade feststellen, dass es die Windows-MessageBox wohl auch nicht anders macht.
    Das Graue unten ist meine Taskleiste und die Zahlen gehen auch bis 1000...

    Also Entweder so wie du bereits vorgeschlagen hast mit einer Scrollbar oder wie ich angefangen hatte, versuchen den String selber umzubrechen, um zumindest ... am Ende noch anhängen zu können.
    Zu viel Text ist dann eben einfach zu viel Text.

    Oder gibt es eine einfache Möglichkeit festzustellen, ob der gesamte Text angezeigt werden kann und wenn nein, bis wohin er angezeit wird?
    Zum Feststellen, ob der Text angezeigt werden kann, wäre mein spontaner Vorschlag mittels TextRenderer.MeasureText() den Text zu messen und mit der Labelgröße zu vergleichen.
    Ist das Label <= der gemessenen Textgröße, kann der Text komplett angezeigt werden...

    EDIT:
    @VaporiZed Vielleicht ist das auch noch interessant für dich;
    Damit die Button-Texte nicht fest einprogrammiert, sondern mit der Systemsprache umgeschaltet werden, hab ich den API-Call MB_GetString in der user32.dll verwendet.
    Dazu muss zunächst der DLL-Import angegeben werden:

    C#-Quellcode

    1. [DllImport( "user32.dll", SetLastError = true, CharSet = CharSet.Unicode )]
    2. private static extern IntPtr MB_GetString(int strId);

    Dann habe ich mir ein Enum erstellt, welches die anzufordernden IDs für die Texte beinhaltet:

    C#-Quellcode

    1. private enum DialogBoxCommandID : int
    2. {
    3. IDOK = 0,
    4. IDCANCEL = 1,
    5. IDABORT = 2,
    6. IDRETRY = 3,
    7. IDIGNORE = 4,
    8. IDYES = 5,
    9. IDNO = 6,
    10. IDCLOSE = 7,
    11. IDHELP = 8,
    12. IDTRYAGAIN = 9,
    13. IDCONTINUE = 10
    14. }

    Anschließend noch eine Funktion, die den entsprechenden String in Systemsprache zurück gibt:

    C#-Quellcode

    1. private string GetCultureText(DialogBoxCommandID id)
    2. {
    3. string result = null;
    4. try
    5. {
    6. //Reference:http://pinvoke.net/default.aspx/user32.MB_GetString
    7. IntPtr ptr = MB_GetString( (int)id );
    8. if( ptr != null ) result = Marshal.PtrToStringAuto( ptr ).Replace( "&", "" );
    9. }
    10. catch (Exception ex)
    11. { Console.WriteLine( "Error at API call 'MB_GetString' in 'user32.dll': " + ex.Message ); }
    12. if (result == null) result = id.ToString();
    13. return result;
    14. }
    Bilder
    • MessageBox.jpg

      28,44 kB, 130×1.080, 62 mal angesehen

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „TRiViUM“ ()