<sub id="73hld"><meter id="73hld"></meter></sub><rp id="73hld"><big id="73hld"><listing id="73hld"></listing></big></rp>

    <th id="73hld"><meter id="73hld"><dfn id="73hld"></dfn></meter></th>

      <th id="73hld"></th>
          <th id="73hld"><form id="73hld"><dfn id="73hld"></dfn></form></th>
          書籍文庫  |  文檔資料  |  最近更新  |  MAP  |  TAG  | 
          注冊
          手機版
          就愛閱讀網
          當前位置:首頁 > 電腦辦公 > 電腦設計 > 程序設計 > 介紹一款C#中可攜帶附加消息的增強消息框(MessageBoxEx)

          介紹一款C#中可攜帶附加消息的增強消息框(MessageBoxEx)

          分享人:flywind_0 來源:互聯網 時間:2018-10-12 16:18:29 閱讀:0
          一個可攜帶附加消息的增強消息框MessageBoxEx分享給大家,具有一定的參考價值,感興趣的小伙伴們可以參考一下

          --------------201507160917更新---------------

          無意中發現標準消息框在Windows7是有聲音的,只是在Windows server 2008(R2)無聲,而我用的剛好是后者,所以誤以為是MessageBeep API在所有NT6系統都不工作造成~汗,有人在stackoverflow也提過這問題。但我仍然決定使用PlaySound API,不做修改
          將聲音處理交給ProcessIcon方法負責。之前考慮松耦合,所以將MessageBoxIcon和聲音分開處理,但其實聲音就是根據前者而來,兩者天然就是耦合的,分開處理多此一舉

          --------------201507091034更新---------------

          首先感謝猿友E204在回復中的反饋。

          解決雙擊【詳細信息】按鈕造成的Checked狀態改變問題,辦法是讓ToggleButton忽略WM_LBUTTONDBLCLK消息
          修正收起詳細信息區邏輯,改為直接取用plAttachZone.Height。之前是取ExpandHeight,會造成視覺體驗問題

          --------------201507082014原文(已更新)---------------

          適用于:.net 2.0+的Winform項目

          樣子:

          有損錄制+制圖的原因不可能原樣展示出真實效果,可至文章結尾下載Demo體驗。

          功能和特點:

          • 相對父窗體居中

          • 可附帶附加消息。附加消息可以是string和Exception類型,【詳細信息】按鈕會根據是否傳入附加信息顯示和隱藏。傳入Exception實例時,呈現的是exception.ToString(),也就是可能攜帶StackTrace信息,所以如果你只是想呈現異常文本,還是老實傳入ex.Message

          • 展開/收起附加信息時有動畫效果。實用為王的你亦可設置EnableAnimate=false關閉動畫效果

          • 在Windows Server 2008 R2(未測試其它服務器系統)也有聲音反饋。標準消息框在個人系統(XP/Win7等)是有聲音的,但在srv08卻沒有。同時亦提供了EnableSound屬性允許你關閉聲音反饋

          • 移除了標準MessageBox提供的IWin32Window、MessageBoxOptions和Help相關參數,原因是我用不到,懶得實現

          • 可拖拉改變消息框尺寸,消息文本和附加文本會隨窗體大小重排。這是標準消息框未提供的能力。改變尺寸分兩種情況有不同的行為:①詳細信息未展開時,改變的是主消息區大小;②詳細信息展開時,改變的是詳細信息區的大小

          總體來說,此消息框比較適合用在需要反饋大量消息文本的場合,用標準消息框的話,文本太多可能會使消息框超出屏幕大小,比如codeproject.com上這位老兄舉的例子,由于標準消息框不具備改變窗體大小的能力,將導致部分消息無法讓用戶看到。而就算沒有超出屏幕,一下子讓用戶面對那么多消息文字,體驗也不地道。使用本消息框就可以解決此類問題,比如可以將扼要信息顯示在主消息區,將大量的明細消息(例如批量處理中的單項處理情況)、次要消息、異常信息等放置在詳細信息區,由用戶或IT支持人員自己去展開獲取這些信息。同時,在沒有附加消息的時候,你仍然可以像標準消息框一樣使用它,所以,如果你跟我一樣不會用到標準消息框的IWin32Window、MessageBoxOptions和Help相關參數的話,基本上你可以在整個項目中全程用此消息框替換掉標準消息框,別忘了相比標準消息框,它還具備了可縮放、相對父窗體居中等額外能力。總言之,你值得擁有。至于如果你擔心性能問題,這個~我想這么說,我對自己的代碼質量還是有點信心的。也希望能得大俠指出槽點,感激!

          使用說明:

          先看公開成員:

          1

          2

          3

          4

          5

          6

          7

          8

          9

          10

          11

          12

          13

          14

          //靜態屬性

          MessageBoxEx.EnableAnimate

          MessageBoxEx.EnableSound

           

          //靜態方法

          MessageBoxEx.Show(string, string, string)

          MessageBoxEx.Show(string, string, string, MessageBoxButtons)

          MessageBoxEx.Show(string, string, string, MessageBoxButtons, MessageBoxIcon)

          MessageBoxEx.Show(string, string, string, MessageBoxButtons, MessageBoxIcon, MessageBoxDefaultButton)

           

          MessageBoxEx.Show(string, string, Exception)

          MessageBoxEx.Show(string, string, Exception, MessageBoxButtons)

          MessageBoxEx.Show(string, string, Exception, MessageBoxButtons, MessageBoxIcon)

          MessageBoxEx.Show(string, string, Exception, MessageBoxButtons, MessageBoxIcon, MessageBoxDefaultButton)

          屬性EnableAnimate和EnableSound上面提過,分別是用來啟用/關閉動畫、聲音效果的,默認是都啟用。倆屬性影響范圍是全局的,比如設置EnableAnimate = false后,之后彈出的MessageBoxEx都沒有動畫效果,直到重新設為true,EnableSound亦然。最佳實踐是將它倆與用戶偏好設置相關聯,允許用戶自主控制

          方法則只有一個:Show(),從重載列表你大概都能知道如何使用。其中第3個參數就是附加消息,可接受string和Exception類的實例,其余參數的位置和意義與標準消息框一致。簡要示例如下:

          1

          2

          MessageBoxEx.Show("主消息", "標題", "附加消息", MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1);

          MessageBoxEx.Show("主消息", "標題", ex, MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1);

          前3個參數可以放心為null,內部有處理,后面的枚舉你也null不了,如果傳入無效枚舉值,會拋異常

          只有3個string參數的那個方法,后面倆參數是可選的。所以不講究消息體驗的你仍然可以這樣使用:

          1

          2

          MessageBoxEx.Show("阿斯頓發");

          MessageBoxEx.Show("阿斯頓發", "士大夫");

          方案源碼:

          代碼不少,原因自然是有的,有興趣的童鞋請看后面的實現說明。另外,千萬不要認為代碼量跟性能有直接關系,有時候更多的代碼恰恰是為了提升性能而存在,有時候則是為了健壯性。

          1

          2

          3

          4

          5

          6

          7

          8

          9

          10

          11

          12

          13

          14

          15

          16

          17

          18

          19

          20

          21

          22

          23

          24

          25

          26

          27

          28

          29

          30

          31

          32

          33

          34

          35

          36

          37

          38

          39

          40

          41

          42

          43

          44

          45

          46

          47

          48

          49

          50

          51

          52

          53

          54

          55

          56

          57

          58

          59

          60

          61

          62

          63

          64

          65

          66

          67

          68

          69

          70

          71

          72

          73

          74

          75

          76

          77

          78

          79

          80

          81

          82

          83

          84

          85

          86

          87

          88

          89

          90

          91

          92

          93

          94

          95

          96

          97

          98

          99

          100

          101

          102

          103

          104

          105

          106

          107

          108

          109

          110

          111

          112

          113

          114

          115

          116

          117

          118

          119

          120

          121

          122

          123

          124

          125

          126

          127

          128

          129

          130

          131

          132

          133

          134

          135

          136

          137

          138

          139

          140

          141

          142

          143

          144

          145

          146

          147

          148

          149

          150

          151

          152

          153

          154

          155

          156

          157

          158

          159

          160

          161

          162

          163

          164

          165

          166

          167

          168

          169

          170

          171

          172

          173

          174

          175

          176

          177

          178

          179

          180

          181

          182

          183

          184

          185

          186

          187

          188

          189

          190

          191

          192

          193

          194

          195

          196

          197

          198

          199

          200

          201

          202

          203

          204

          205

          206

          207

          208

          209

          210

          211

          212

          213

          214

          215

          216

          217

          218

          219

          220

          221

          222

          223

          224

          225

          226

          227

          228

          229

          230

          231

          232

          233

          234

          235

          236

          237

          238

          239

          240

          241

          242

          243

          244

          245

          246

          247

          248

          249

          250

          251

          252

          253

          254

          255

          256

          257

          258

          259

          260

          261

          262

          263

          264

          265

          266

          267

          268

          269

          270

          271

          272

          273

          274

          275

          276

          277

          278

          279

          280

          281

          282

          283

          284

          285

          286

          287

          288

          289

          290

          291

          292

          293

          294

          295

          296

          297

          298

          299

          300

          301

          302

          303

          304

          305

          306

          307

          308

          309

          310

          311

          312

          313

          314

          315

          316

          317

          318

          319

          320

          321

          322

          323

          324

          325

          326

          327

          328

          329

          330

          331

          332

          333

          334

          335

          336

          337

          338

          339

          340

          341

          342

          343

          344

          345

          346

          347

          348

          349

          350

          351

          352

          353

          354

          355

          356

          357

          358

          359

          360

          361

          362

          363

          364

          365

          366

          367

          368

          369

          370

          371

          372

          373

          374

          375

          376

          377

          378

          379

          380

          381

          382

          383

          384

          385

          386

          387

          388

          389

          390

          391

          392

          393

          394

          395

          396

          397

          398

          399

          400

          401

          402

          403

          404

          405

          406

          407

          408

          409

          410

          411

          412

          413

          414

          415

          416

          417

          418

          419

          420

          421

          422

          423

          424

          425

          426

          427

          428

          429

          430

          431

          432

          433

          434

          435

          436

          437

          438

          439

          440

          441

          442

          443

          444

          445

          446

          447

          448

          449

          450

          451

          452

          453

          454

          455

          456

          457

          458

          459

          460

          461

          462

          463

          464

          465

          466

          467

          468

          469

          470

          471

          472

          473

          474

          475

          476

          477

          478

          479

          480

          481

          482

          483

          484

          485

          486

          487

          488

          489

          490

          491

          492

          493

          494

          495

          496

          497

          498

          499

          500

          501

          502

          503

          504

          505

          506

          507

          508

          509

          510

          511

          512

          513

          514

          515

          516

          517

          518

          519

          520

          521

          522

          523

          524

          525

          526

          527

          528

          529

          530

          531

          532

          533

          534

          535

          536

          537

          538

          539

          540

          541

          542

          543

          544

          545

          546

          547

          548

          549

          550

          551

          552

          553

          554

          555

          556

          557

          558

          559

          560

          561

          562

          563

          564

          565

          566

          567

          568

          569

          570

          571

          572

          573

          574

          575

          576

          577

          578

          579

          580

          581

          582

          583

          584

          585

          586

          587

          588

          589

          590

          591

          592

          593

          594

          595

          596

          597

          598

          599

          600

          601

          602

          603

          604

          605

          606

          607

          608

          609

          610

          611

          612

          613

          614

          615

          616

          617

          618

          619

          620

          621

          622

          623

          624

          625

          626

          627

          628

          629

          630

          631

          632

          633

          634

          635

          636

          637

          638

          639

          640

          641

          642

          643

          644

          645

          646

          647

          648

          649

          650

          651

          652

          653

          654

          655

          656

          657

          658

          659

          660

          661

          662

          663

          664

          665

          666

          667

          668

          669

          670

          671

          672

          673

          674

          675

          676

          677

          678

          679

          680

          681

          682

          683

          684

          685

          686

          687

          688

          689

          690

          691

          692

          693

          694

          695

          696

          697

          698

          699

          700

          701

          702

          703

          704

          705

          706

          707

          708

          709

          710

          711

          712

          713

          714

          715

          716

          717

          718

          719

          720

          721

          722

          723

          724

          725

          726

          727

          728

          729

          730

          731

          732

          733

          734

          735

          736

          737

          738

          739

          740

          741

          742

          743

          744

          745

          746

          747

          748

          749

          750

          751

          752

          753

          754

          755

          756

          757

          758

          759

          760

          761

          762

          763

          764

          765

          766

          767

          768

          769

          770

          771

          772

          773

          774

          775

          776

          777

          778

          779

          780

          781

          782

          783

          784

          785

          786

          787

          788

          789

          790

          791

          792

          793

          794

          795

          796

          797

          798

          799

          800

          801

          802

          803

          804

          805

          806

          807

          808

          809

          810

          811

          812

          813

          814

          815

          816

          817

          818

          819

          820

          821

          822

          823

          824

          825

          826

          827

          828

          829

          830

          831

          832

          833

          834

          835

          836

          837

          838

          839

          840

          841

          842

          843

          844

          845

          846

          847

          848

          849

          850

          851

          852

          853

          854

          855

          856

          857

          858

          859

          860

          861

          862

          863

          864

          865

          866

          867

          868

          869

          870

          871

          872

          873

          874

          875

          876

          877

          878

          879

          880

          881

          882

          883

          884

          885

          886

          887

          888

          889

          890

          891

          892

          893

          894

          895

          896

          897

          898

          899

          900

          901

          902

          903

          904

          905

          906

          907

          908

          909

          910

          911

          912

          913

          914

          915

          916

          917

          918

          919

          920

          921

          922

          923

          924

          925

          926

          927

          928

          929

          930

          931

          932

          933

          934

          935

          936

          937

          938

          939

          940

          941

          942

          943

          944

          945

          946

          947

          948

          949

          950

          951

          952

          953

          954

          955

          956

          957

          958

          959

          960

          961

          962

          963

          964

          965

          966

          967

          968

          969

          970

          971

          972

          973

          974

          975

          976

          977

          978

          979

          980

          981

          982

          983

          984

          985

          986

          987

          988

          989

          990

          991

          992

          993

          994

          995

          996

          997

          998

          999

          1000

          1001

          1002

          1003

          1004

          1005

          1006

          1007

          1008

          1009

          1010

          1011

          1012

          1013

          1014

          1015

          1016

          1017

          1018

          1019

          1020

          1021

          1022

          1023

          1024

          1025

          1026

          1027

          1028

          1029

          1030

          1031

          1032

          1033

          1034

          1035

          1036

          1037

          1038

          1039

          1040

          1041

          1042

          1043

          1044

          1045

          1046

          1047

          1048

          1049

          1050

          1051

          1052

          1053

          1054

          1055

          1056

          1057

          1058

          1059

          1060

          1061

          1062

          1063

          1064

          1065

          1066

          1067

          1068

          1069

          1070

          1071

          1072

          1073

          1074

          1075

          1076

          1077

          1078

          1079

          1080

          1081

          1082

          1083

          1084

          1085

          1086

          1087

          1088

          1089

          1090

          1091

          1092

          1093

          1094

          1095

          1096

          1097

          1098

          1099

          1100

          1101

          1102

          1103

          1104

          1105

          1106

          1107

          1108

          1109

          1110

          1111

          1112

          1113

          1114

          1115

          1116

          1117

          1118

          1119

          1120

          1121

          1122

          1123

          1124

          1125

          1126

          1127

          1128

          1129

          1130

          1131

          1132

          1133

          1134

          1135

          1136

          1137

          1138

          1139

          1140

          1141

          1142

          1143

          1144

          1145

          1146

          1147

          1148

          1149

          1150

          1151

          1152

          1153

          1154

          1155

          1156

          1157

          1158

          1159

          1160

          1161

          1162

          1163

          1164

          1165

          1166

          1167

          1168

          1169

          1170

          1171

          1172

          1173

          1174

          1175

          1176

          1177

          1178

          1179

          1180

          1181

          1182

          1183

          1184

          1185

          1186

          1187

          1188

          1189

          1190

          1191

          1192

          1193

          1194

          1195

          1196

          1197

          1198

          1199

          1200

          using System;

          using System.ComponentModel;

          using System.Drawing;

          using System.IO;

          using System.Runtime.InteropServices;

          using System.Threading;

          using System.Windows.Forms;

           

          namespace AhDung.WinForm

          {

           /// <summary>

           /// 可以攜帶詳細信息的消息框

           /// </summary>

           public static class MessageBoxEx

           {

           //異常消息文本

           private const string InvalidButtonExString = "按鈕參數不是有效的枚舉項!";

           private const string InvalidIconExString = "圖標參數不是有效的枚舉項!";

           private const string InvalidDfButtonExString = "默認按鈕參數不是有效的枚舉項!";

           

           /// <summary>

           /// 是否啟用動畫效果

           /// </summary>

           public static bool EnableAnimate { get; set; }

           

           /// <summary>

           /// 是否啟用聲音反饋

           /// </summary>

           public static bool EnableSound { get; set; }

           

           //靜態構造

           static MessageBoxEx()

           {

            //默認啟用動畫+聲音

            EnableAnimate = true;

            EnableSound = true;

           }

           

           #region 公開方法

           

           /// <summary>

           /// 顯示消息框

           /// </summary>

           /// <param name="message">消息文本</param>

           /// <param name="caption">消息框標題</param>

           /// <param name="attachMessage">附加消息</param>

           public static DialogResult Show(string message, string caption = null, string attachMessage = null)

           {

            return ShowCore(message, caption, attachMessage, MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1);

           }

           

           /*下面這仨弄成重載而不是可選方法是為了避免不必要的參數檢查*/

           

           /// <summary>

           /// 顯示消息框

           /// </summary>

           /// <param name="message">消息文本</param>

           /// <param name="caption">消息框標題</param>

           /// <param name="attachMessage">附加消息</param>

           /// <param name="buttons">按鈕組合</param>

           public static DialogResult Show(string message, string caption, string attachMessage, MessageBoxButtons buttons)

           {

            if (!Enum.IsDefined(typeof(MessageBoxButtons), buttons)) { throw new InvalidEnumArgumentException(InvalidButtonExString); }

           

            return ShowCore(message, caption, attachMessage, buttons, MessageBoxIcon.None, MessageBoxDefaultButton.Button1);

           }

           

           /// <summary>

           /// 顯示消息框

           /// </summary>

           /// <param name="message">消息文本</param>

           /// <param name="caption">消息框標題</param>

           /// <param name="attachMessage">附加消息</param>

           /// <param name="buttons">按鈕組合</param>

           /// <param name="icon">圖標</param>

           public static DialogResult Show(string message, string caption, string attachMessage, MessageBoxButtons buttons, MessageBoxIcon icon)

           {

            if (!Enum.IsDefined(typeof(MessageBoxButtons), buttons)) { throw new InvalidEnumArgumentException(InvalidButtonExString); }

            if (!Enum.IsDefined(typeof(MessageBoxIcon), icon)) { throw new InvalidEnumArgumentException(InvalidIconExString); }

           

            return ShowCore(message, caption, attachMessage, buttons, icon, MessageBoxDefaultButton.Button1);

           }

           

           /// <summary>

           /// 顯示消息框

           /// </summary>

           /// <param name="message">消息文本</param>

           /// <param name="caption">消息框標題</param>

           /// <param name="attachMessage">附加消息</param>

           /// <param name="buttons">按鈕組合</param>

           /// <param name="icon">圖標</param>

           /// <param name="defaultButton">默認按鈕</param>

           public static DialogResult Show(string message, string caption, string attachMessage, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton)

           {

            if (!Enum.IsDefined(typeof(MessageBoxButtons), buttons)) { throw new InvalidEnumArgumentException(InvalidButtonExString); }

            if (!Enum.IsDefined(typeof(MessageBoxIcon), icon)) { throw new InvalidEnumArgumentException(InvalidIconExString); }

            if (!Enum.IsDefined(typeof(MessageBoxDefaultButton), defaultButton)) { throw new InvalidEnumArgumentException(InvalidDfButtonExString); }

           

            return ShowCore(message, caption, attachMessage, buttons, icon, defaultButton);

           }

           

           /********傳入異常的重載********/

           

           /// <summary>

           /// 顯示消息框

           /// </summary>

           /// <param name="message">消息文本</param>

           /// <param name="caption">消息框標題</param>

           /// <param name="exception">異常實例</param>

           public static DialogResult Show(string message, string caption, Exception exception)

           {

            return Show(message, caption, exception == null ? string.Empty : exception.ToString());

           }

           

           /// <summary>

           /// 顯示消息框

           /// </summary>

           /// <param name="message">消息文本</param>

           /// <param name="caption">消息框標題</param>

           /// <param name="exception">異常實例</param>

           /// <param name="buttons">按鈕組合</param>

           public static DialogResult Show(string message, string caption, Exception exception, MessageBoxButtons buttons)

           {

            return Show(message, caption, exception == null ? string.Empty : exception.ToString(), buttons);

           }

           

           /// <summary>

           /// 顯示消息框

           /// </summary>

           /// <param name="message">消息文本</param>

           /// <param name="caption">消息框標題</param>

           /// <param name="exception">異常實例</param>

           /// <param name="buttons">按鈕組合</param>

           /// <param name="icon">圖標</param>

           public static DialogResult Show(string message, string caption, Exception exception, MessageBoxButtons buttons, MessageBoxIcon icon)

           {

            return Show(message, caption, exception == null ? string.Empty : exception.ToString(), buttons, icon);

           }

           

           /// <summary>

           /// 顯示消息框

           /// </summary>

           /// <param name="message">消息文本</param>

           /// <param name="caption">消息框標題</param>

           /// <param name="exception">異常實例</param>

           /// <param name="buttons">按鈕組合</param>

           /// <param name="icon">圖標</param>

           /// <param name="defaultButton">默認按鈕</param>

           public static DialogResult Show(string message, string caption, Exception exception, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton)

           {

            return Show(message, caption, exception == null ? string.Empty : exception.ToString(), buttons, icon, defaultButton);

           }

           

           #endregion

           

           //內部方法,不檢查參數有效性

           private static DialogResult ShowCore(string message, string caption, string attachMessage, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton)

           {

            using (MessageForm f = new MessageForm(message, caption, buttons, icon, defaultButton, attachMessage, EnableAnimate, EnableSound))

            {

            return f.ShowDialog();

            }

           }

           

           /*----------------

            下面是消息窗體相關

            ---------------*/

           

           /// <summary>

           /// 消息窗體

           /// </summary>

           /// <remarks>參數有效性由MessageBoxEx負責</remarks>

           private class MessageForm : Form

           {

            /* todo 存在問題:

            * 當消息區文本非常非常多時,且反復進行改變消息框窗口大小、位置、展開收起的操作,那么在某次展開時

            詳細信息文本框可能會在原位置(即消息區內某rect)瞬閃一下,

            原因是文本框控件在顯示時總會在原位置WM_NCPAINT + WM_ERASEBKGND一下,暫無解決辦法。

            實際應用中碰到的幾率很小,就算碰到,影響也可以忽略。

            */

           

            #region 控件初始化

           

            /// <summary>

            /// 必需的設計器變量。

            /// </summary>

            private System.ComponentModel.IContainer components = null;

           

            /// <summary>

            /// 清理所有正在使用的資源。

            /// </summary>

            /// <param name="disposing">如果應釋放托管資源,為 true;否則為 false。</param>

            protected override void Dispose(bool disposing)

            {

            if (disposing && (components != null))

            {

             components.Dispose();

            }

            base.Dispose(disposing);

            }

           

            #region Windows 窗體設計器生成的代碼

           

            /// <summary>

            /// 設計器支持所需的方法 - 不要

            /// 使用代碼編輯器修改此方法的內容。

            /// </summary>

            private void InitializeComponent()

            {

            this.button3 = new System.Windows.Forms.Button();

            this.txbAttach = new TextBoxUnSelectAllable();

            this.button2 = new System.Windows.Forms.Button();

            this.button1 = new System.Windows.Forms.Button();

            this.plButtonsZone = new AhDung.WinForm.MessageBoxEx.MessageForm.PanelBasic();

            this.ckbToggle = new AhDung.WinForm.MessageBoxEx.MessageForm.ToggleButton(this.UseAnimate);

            this.plAttachZone = new AhDung.WinForm.MessageBoxEx.MessageForm.PanelBasic();

            this.lbMsg = new AhDung.WinForm.MessageBoxEx.MessageForm.MessageViewer();

            this.plButtonsZone.SuspendLayout();

            this.plAttachZone.SuspendLayout();

            this.SuspendLayout();

            //

            // button3

            //

            this.button3.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right;

            this.button3.Location = new System.Drawing.Point(320, 8);

            this.button3.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);

            this.button3.Name = "button3";

            this.button3.Size = new System.Drawing.Size(85, 27);

            this.button3.TabIndex = 2;

            //

            // txbAttach

            //

            this.txbAttach.Anchor = ((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)

                | System.Windows.Forms.AnchorStyles.Left)

                | System.Windows.Forms.AnchorStyles.Right;

            this.txbAttach.Location = new System.Drawing.Point(10, 7);

            this.txbAttach.Margin = new System.Windows.Forms.Padding(3, 1, 3, 1);

            this.txbAttach.Name = "txbAttach";

            this.txbAttach.ReadOnly = true;

            this.txbAttach.Multiline = true;

            this.txbAttach.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;

            this.txbAttach.Size = new System.Drawing.Size(395, 105);

            this.txbAttach.TabIndex = 0;

            //

            // button2

            //

            this.button2.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right;

            this.button2.Location = new System.Drawing.Point(229, 8);

            this.button2.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);

            this.button2.Name = "button2";

            this.button2.Size = new System.Drawing.Size(85, 27);

            this.button2.TabIndex = 1;

            //

            // button1

            //

            this.button1.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right;

            this.button1.Location = new System.Drawing.Point(138, 8);

            this.button1.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);

            this.button1.Name = "button1";

            this.button1.Size = new System.Drawing.Size(85, 27);

            this.button1.TabIndex = 0;

            //

            // plButtonsZone

            //

            this.plButtonsZone.Controls.Add(this.ckbToggle);

            this.plButtonsZone.Controls.Add(this.button1);

            this.plButtonsZone.Controls.Add(this.button2);

            this.plButtonsZone.Controls.Add(this.button3);

            this.plButtonsZone.Dock = System.Windows.Forms.DockStyle.Bottom;

            this.plButtonsZone.Location = new System.Drawing.Point(0, 96);

            this.plButtonsZone.Margin = new System.Windows.Forms.Padding(3, 1, 3, 1);

            this.plButtonsZone.Name = "plButtonsZone";

            this.plButtonsZone.Size = new System.Drawing.Size(415, 36);

            this.plButtonsZone.TabIndex = 1;

            //

            // ckbToggle

            //

            this.ckbToggle.Location = new System.Drawing.Point(10, 8);

            this.ckbToggle.Name = "ckbToggle";

            this.ckbToggle.Size = new System.Drawing.Size(93, 27);

            this.ckbToggle.TabIndex = 3;

            this.ckbToggle.Text = "詳細信息(&D)";

            this.ckbToggle.CheckedChanged += this.ckbToggle_CheckedChanged;

            //

            // plAttachZone

            //

            this.plAttachZone.Controls.Add(this.txbAttach);

            this.plAttachZone.Dock = System.Windows.Forms.DockStyle.Fill;

            this.plAttachZone.Location = new System.Drawing.Point(0, 130);

            this.plAttachZone.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);

            this.plAttachZone.Name = "plAttachZone";

            this.plAttachZone.Size = new System.Drawing.Size(415, 114);

            this.plAttachZone.TabIndex = 2;

            this.plAttachZone.Visible = false;

            //

            // lbMsg

            //

            this.lbMsg.Dock = System.Windows.Forms.DockStyle.Fill;

            this.lbMsg.Icon = null;

            this.lbMsg.Location = new System.Drawing.Point(0, 0);

            this.lbMsg.Name = "lbMsg";

            this.lbMsg.Padding = new System.Windows.Forms.Padding(21, 18, 21, 18);

            //this.lbMsg.Size = new System.Drawing.Size(415, 96);

            this.lbMsg.TabIndex = 0;

            //

            // FmMsg

            //

            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;

            //this.ClientSize = new System.Drawing.Size(415, 261);

            this.Controls.Add(this.lbMsg);

            this.Controls.Add(this.plButtonsZone);

            this.Controls.Add(this.plAttachZone);

            this.DoubleBuffered = true;

            this.MaximizeBox = false;

            this.Name = "MessageForm";

            this.Padding = new System.Windows.Forms.Padding(0, 0, 0, 17);

            this.ShowIcon = false;

            this.ShowInTaskbar = false;

            this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Show;

            this.plButtonsZone.ResumeLayout(false);

            this.plAttachZone.ResumeLayout(false);

            this.plAttachZone.PerformLayout();

            this.ResumeLayout(false);

            }

           

            #endregion

           

            private ToggleButton ckbToggle;

            private TextBoxUnSelectAllable txbAttach;

            private MessageViewer lbMsg;

            private System.Windows.Forms.Button button2;

            private System.Windows.Forms.Button button1;

            private PanelBasic plButtonsZone;

            private PanelBasic plAttachZone;

            private System.Windows.Forms.Button button3;

           

            #endregion

           

            /// <summary>

            /// 最大默認窗體客戶區寬度

            /// </summary>

            const int MaxClientWidth = 700;

           

            string messageSound;//存儲供PlaySound API使用的系統消息音別名,在ProcessIcon中賦值,OnShown中取用

           

            int expandHeight;

            /// <summary>

            /// 詳細信息區展開高度

            /// </summary>

            private int ExpandHeight

            {

            get { return expandHeight < 150 ? 150 : expandHeight; }

            set { expandHeight = value; }

            }

           

            #region 屬性

           

            /// <summary>

            /// 是否啟用動畫效果

            /// </summary>

            /// <remarks>此處還弄該屬性是為了保證窗體類的獨立性</remarks>

            private bool UseAnimate { get; set; }

           

            /// <summary>

            /// 是否啟用聲音反饋

            /// </summary>

            /// <remarks>此處還弄該屬性是為了保證窗體類的獨立性</remarks>

            private bool UseSound { get; set; }

           

            /// <summary>

            /// 消息按鈕

            /// </summary>

            private MessageBoxButtons MessageButtons { get; set; }

           

            /// <summary>

            /// 消息圖標

            /// </summary>

            private MessageBoxIcon MessageIcon { get; set; }

           

            /// <summary>

            /// 默認按鈕

            /// </summary>

            private MessageBoxDefaultButton DefaultButton { get; set; }

           

            #endregion

           

            /// <summary>

            /// 創建消息窗體

            /// </summary>

            private MessageForm(bool enableAnimate)

            {

            this.UseAnimate = enableAnimate;//須盡早設置,要供展開按鈕初始化用

            InitializeComponent();

            this.StartPosition = Form.ActiveForm == null ? FormStartPosition.CenterScreen : FormStartPosition.CenterParent;

            this.Font = SystemFonts.MessageBoxFont;

           

            //注冊事件

            this.button1.Click += button_Click;

            this.button2.Click += button_Click;

            this.button3.Click += button_Click;

            this.plAttachZone.Resize += plAttachZone_Resize;

            }

           

            /// <summary>

            /// 創建消息窗體

            /// </summary>

            public MessageForm(string message, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, string attachMessage, bool enableAnimate, bool enableSound)

            : this(enableAnimate)

            {

            this.lbMsg.Text = message;

            this.Text = caption;

            this.txbAttach.Text = attachMessage;

            this.MessageButtons = buttons;

            this.MessageIcon = icon;

            this.DefaultButton = defaultButton;

            this.UseSound = enableSound;

            }

           

            #region 重寫基類方法

           

            protected override void OnLoad(EventArgs e)

            {

            //須在計算各種尺寸前搞掂

            ProcessIcon();

            ProcessButtons();

           

            this.MinimumSize = SizeFromClientSize(new Size(GetPanelButtonMinWidth(), GetClientMinHeight()));

           

            //參數意義定為客戶區最大大小,所以需刨掉非客戶區高度后傳入

            this.ClientSize = this.GetPreferredSize(new Size(MaxClientWidth, Screen.PrimaryScreen.WorkingArea.Height - (this.Height - this.ClientSize.Height)));

           

            base.OnLoad(e);

            }

           

            protected override void OnShown(EventArgs e)

            {

            //設置默認按鈕焦點。須在OnShown中設置按鈕焦點才有用

            Button dfBtn;

            if ((dfBtn = this.AcceptButton as Button) != null)

            {

             dfBtn.Focus();

            }

           

            //播放消息提示音

            if (this.UseSound) { PlaySystemSound(this.messageSound); }

           

            base.OnShown(e);

            }

           

            //重寫窗體參數

            protected override CreateParams CreateParams

            {

            get

            {

             CreateParams prms = base.CreateParams;

           

             if ((Convert.ToInt32(this.MessageButtons) & 1) == 0) //沒有Cancel按鈕時屏蔽關閉按鈕,剛好在偶數項

             {

             prms.ClassStyle |= 0x200;

             }

           

             return prms;

            }

            }

           

            /// <summary>

            /// 計算合適的窗口尺寸

            /// </summary>

            /// <param name="proposedSize">該參數此處定義為客戶區可設置的最大尺寸</param>

            public override Size GetPreferredSize(Size proposedSize)

            {

            int reservedHeight = plButtonsZone.Height + Padding.Bottom;

            Size size = lbMsg.GetPreferredSize(new Size(proposedSize.Width, proposedSize.Height - reservedHeight));

            size.Height += reservedHeight;

            return size;

            }

           

            #endregion

           

            #region 事件處理方法

           

            //展開收起

            private void ckbToggle_CheckedChanged(object sender, EventArgs e)

            {

            this.SuspendLayout();

           

            if (ckbToggle.Checked)

            {

             plButtonsZone.SendToBack();

             lbMsg.SendToBack();

           

             lbMsg.Dock = DockStyle.Top;

             plButtonsZone.Dock = DockStyle.Top;

           

             ChangeFormHeight(ExpandHeight);

             plAttachZone.Visible = true;

            }

            else

            {

             ExpandHeight = plAttachZone.Height;//為再次展開記憶高度

             plAttachZone.Visible = false;

             ChangeFormHeight(-plAttachZone.Height);//收起時直接取pl高度,不要取ExpandHeight

           

             plButtonsZone.SendToBack();

           

             plButtonsZone.Dock = DockStyle.Bottom;

             lbMsg.Dock = DockStyle.Fill;

            }

           

            this.ResumeLayout();

            }

           

            //按鈕事件

            private void button_Click(object sender, EventArgs e)

            {

            this.DialogResult = (DialogResult)((sender as Button).Tag);

            }

           

            //用戶手工收完詳細區則觸發折疊

            private void plAttachZone_Resize(object sender, EventArgs e)

            {

            if (ckbToggle.Checked && plAttachZone.Height == 0)

            {

             ckbToggle.Checked = false;

            }

            }

           

            #endregion

           

            #region 輔助+私有方法

           

            /// <summary>

            /// 處理按鈕相關

            /// </summary>

            private void ProcessButtons()

            {

            this.ckbToggle.Visible = txbAttach.Text.Trim().Length != 0; //無詳細信息就不顯示展開按鈕

           

            int btnCount = 3; //按鈕數量

           

            switch (MessageButtons) //老實用case,可讀點

            {

             case MessageBoxButtons.AbortRetryIgnore:

             button1.Text = "中止(&A)"; button1.Tag = DialogResult.Abort;

             button2.Text = "重試(&R)"; button2.Tag = DialogResult.Retry;

             button3.Text = "忽略(&I)"; button3.Tag = DialogResult.Ignore;

             break;

             case MessageBoxButtons.OK:

             button1.Visible = false;

             button2.Visible = false;

             button3.Text = "確定"; button3.Tag = DialogResult.OK;

             btnCount = 1;

             break;

             case MessageBoxButtons.OKCancel:

             button1.Visible = false;

             button2.Text = "確定"; button2.Tag = DialogResult.OK;

             button3.Text = "取消"; button3.Tag = DialogResult.Cancel;

             btnCount = 2;

             break;

             case MessageBoxButtons.RetryCancel:

             button1.Visible = false;

             button2.Text = "重試(&R)"; button2.Tag = DialogResult.Retry;

             button3.Text = "取消"; button3.Tag = DialogResult.Cancel;

             btnCount = 2;

             break;

             case MessageBoxButtons.YesNo:

             button1.Visible = false;

             button2.Text = "是(&Y)"; button2.Tag = DialogResult.Yes;

             button3.Text = "否(&N)"; button3.Tag = DialogResult.No;

             btnCount = 2;

             break;

             case MessageBoxButtons.YesNoCancel:

             button1.Text = "是(&Y)"; button1.Tag = DialogResult.Yes;

             button2.Text = "否(&N)"; button2.Tag = DialogResult.No;

             button3.Text = "取消"; button3.Tag = DialogResult.Cancel;

             break;

             default: break;

            }

           

            //僅有OK和有取消按鈕時設CancelButton

            if ((int)MessageButtons == 0 || ((int)MessageButtons & 1) == 1)

            {

             this.CancelButton = button3;

            }

           

            //處理默認按鈕

            if (btnCount == 1)

            {

             this.AcceptButton = button3;

            }

            else if (btnCount == 2)

            {

             this.AcceptButton = DefaultButton == MessageBoxDefaultButton.Button2 ? button3 : button2;

            }

            else

            {

             Button[] btnArray = { button1, button2, button3 };

             this.AcceptButton = btnArray[Convert.ToInt32(DefaultButton) / 0x100];

            }

            }

           

            /// <summary>

            /// 處理圖標(含聲音)

            /// </summary>

            private void ProcessIcon()

            {

            switch (MessageIcon)

            {

             //MessageBoxIcon.Information同樣

             case MessageBoxIcon.Asterisk:

             lbMsg.Icon = SystemIcons.Information;

             messageSound = "SystemAsterisk";

             break;

           

             //MessageBoxIcon.Hand、MessageBoxIcon.Stop同樣

             case MessageBoxIcon.Error:

             lbMsg.Icon = SystemIcons.Error;

             messageSound = "SystemHand";

             break;

           

             //MessageBoxIcon.Warning同樣

             case MessageBoxIcon.Exclamation:

             lbMsg.Icon = SystemIcons.Warning;

             messageSound = "SystemExclamation";

             break;

           

             case MessageBoxIcon.Question:

             lbMsg.Icon = SystemIcons.Question;

             messageSound = "SystemAsterisk";//Question原本是沒聲音的,此實現讓它蹭一下Information的

             break;

           

             default: //MessageBoxIcon.None

             lbMsg.Icon = null;

             messageSound = "SystemDefault";

             break;

            }

            }

           

            /// <summary>

            /// 計算窗體客戶區最小高度

            /// </summary>

            private int GetClientMinHeight()

            {

            return lbMsg.MinimumHeight + plButtonsZone.Height + Padding.Bottom;

            }

           

            /// <summary>

            /// 計算按鈕區最小寬度

            /// </summary>

            private int GetPanelButtonMinWidth()

            {

            int r = 20 /*左右Padding*/, visibleCount = -1 /*因為兩個以上才會有間距*/;

           

            if (ckbToggle.Visible) { r += ckbToggle.Width; visibleCount++; }

            if (button1.Visible) { r += button1.Width * 3; visibleCount += 3; }

            else if (button2.Visible) { r += button2.Width * 2; visibleCount += 2; }

            else { r += button3.Width; visibleCount++; }

           

            if (visibleCount != -1) { r += visibleCount * 6; } //按鈕間距

           

            return r;

            }

           

            /// <summary>

            /// 改變窗體高度。內部有動畫處理

            /// </summary>

            /// <param name="increment">增量(負數即為減小高度)</param>

            private void ChangeFormHeight(int increment)

            {

            int finalHeight = this.Height + increment; //正確的目標高度

           

            if (!this.UseAnimate) //不使用動畫

            {

             this.Height = finalHeight;

             return;

            }

           

            const int step = 8; //幀數

           

            for (int i = 0; i < step; i++)

            {

             if (i == step - 1) //最后一步直達目標

             {

             this.Height = finalHeight;

             return;

             }

           

             this.Height += increment / step;

           

             Application.DoEvents(); //必要

             Thread.Sleep(10);

            }

            }

           

            /// <summary>

            /// 播放系統事件聲音

            /// </summary>

            /// <remarks>之所以不用MessageBeep API是因為這貨在srv08上不出聲,所以用PlaySound代替</remarks>

            private static void PlaySystemSound(string soundAlias)

            {

            PlaySound(soundAlias, IntPtr.Zero, 0x10000 /*SND_ALIAS*/| 0x1 /*SND_ASYNC*/);

            }

           

            [DllImport("winmm.dll", CharSet = CharSet.Auto)]

            private static extern bool PlaySound([MarshalAs(UnmanagedType.LPWStr)] string soundName, IntPtr hmod, int soundFlags);

           

            #endregion

           

            #region 嵌套類

           

            /// <summary>

            /// 基礎面板

            /// </summary>

            private class PanelBasic : Control

            {

            public PanelBasic()

            {

             SetStyle(ControlStyles.AllPaintingInWmPaint, false);//關鍵,不然其上的ToolBar不正常

             SetStyle(ControlStyles.OptimizedDoubleBuffer, true);//重要。不設置的話控件繪制不正常

             SetStyle(ControlStyles.ContainerControl, true);

             SetStyle(ControlStyles.Selectable, false);

            }

           

            protected override void WndProc(ref Message m)

            {

             //屏蔽WM_ERASEBKGND。防止顯示時在原位置快閃

             //不能通過ControlStyles.AllPaintingInWmPaint=true屏蔽

             //會影響其上的ToolBar

             if (m.Msg == 0x14) { return; }

           

             base.WndProc(ref m);

            }

           

            protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified)

            {

             //防Dock時面板短暫滯留在原位置

             base.SetBoundsCore(x, y, width, height, specified | BoundsSpecified.Y | BoundsSpecified.Width);

            }

            }

           

            /// <summary>

            /// 消息呈現控件

            /// </summary>

            private class MessageViewer : Control

            {

            const TextFormatFlags textFlags = TextFormatFlags.EndEllipsis //未完省略號

                 | TextFormatFlags.WordBreak //允許換行

                 | TextFormatFlags.NoPadding //無邊距

                 | TextFormatFlags.ExternalLeading //行間空白。NT5必須,不然文字擠在一起

                 | TextFormatFlags.TextBoxControl; //避免半行

           

            const int IconSpace = 5; //圖標與文本間距

           

            const float PreferredScale = 13;//最佳文本區塊比例(寬/高)

           

            /// <summary>

            /// 最小高度。不要重寫MinimumSize,那會在窗體移動和縮放時都會執行

            /// </summary>

            public int MinimumHeight

            {

             get

             {

             return (this.Icon != null ? Math.Max(this.Icon.Height, this.FontHeight) : this.FontHeight) + Padding.Vertical;

             }

            }

           

            /// <summary>

            /// 獲取或設置圖標

            /// </summary>

            public Icon Icon { get; set; }

           

            public MessageViewer()

            {

             this.SetStyle(ControlStyles.CacheText, true);

             this.SetStyle(ControlStyles.UserPaint, true);

             this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);

             this.SetStyle(ControlStyles.Selectable, false);

             this.SetStyle(ControlStyles.ResizeRedraw, true); //重要

           

             this.DoubleBuffered = true; //雙緩沖

             BackColor = Environment.OSVersion.Version.Major == 5 ? SystemColors.Control : Color.White;

            }

           

            //防Dock改變尺寸

            protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified)

            {

             base.SetBoundsCore(x, y, width, height, specified | BoundsSpecified.Size);

            }

           

            /// <summary>

            /// 計算合適的消息區尺寸

            /// </summary>

            /// <param name="proposedSize">該參數此處定義為此控件可設置的最大尺寸</param>

            /// <remarks>該方法對太長的單行文本有做比例優化處理,避免用戶擺頭幅度過大扭到脖子</remarks>

            public override Size GetPreferredSize(Size proposedSize)

            {

             if (proposedSize.Width < 10) { proposedSize.Width = int.MaxValue; }

             if (proposedSize.Height < 10) { proposedSize.Height = int.MaxValue; }

           

             int reservedWidth = Padding.Horizontal + (this.Icon == null ? 0 : (this.Icon.Width + IconSpace));

           

             Size wellSize = Size.Empty;

             if (!string.IsNullOrEmpty(this.Text))

             {

             //優化文本塊寬高比例

             Size size = TextRenderer.MeasureText(this.Text, this.Font, new Size(proposedSize.Width - reservedWidth, 0), textFlags);//用指定寬度測量文本面積

             wellSize = Convert.ToSingle(size.Width) / size.Height > PreferredScale //過于寬扁的情況

              ? Size.Ceiling(GetSameSizeWithNewScale(size, PreferredScale))

              : size;

           

             //湊齊整行高,確保尾行顯示

             int lineHeight = TextRenderer.MeasureText(" ", this.Font, new Size(int.MaxValue, 0), textFlags).Height;//單行高,Font.Height不靠譜

             int differ;

             wellSize.Height += (differ = wellSize.Height % lineHeight) == 0 ? 0 : (lineHeight - differ);

             }

             if (this.Icon != null)

             {

             wellSize.Width += this.Icon.Width + IconSpace;

             wellSize.Height = Math.Max(this.Icon.Height, wellSize.Height);

             }

             wellSize += Padding.Size;

           

             //不應超過指定尺寸。寬度在上面已確保不會超過

             if (wellSize.Height > proposedSize.Height) { wellSize.Height = proposedSize.Height; }

           

             return wellSize;

            }

           

            /// <summary>

            /// 重繪

            /// </summary>

            protected override void OnPaint(PaintEventArgs e)

            {

             Graphics g = e.Graphics;

             Rectangle rect = GetPaddedRectangle();

           

             //繪制圖標

             if (this.Icon != null)

             {

             g.DrawIcon(this.Icon, Padding.Left, Padding.Top);

           

             //右移文本區

             rect.X += this.Icon.Width + IconSpace;

             rect.Width -= this.Icon.Width + IconSpace;

           

             //若文字太少,則與圖標垂直居中

             if (this.Text.Length < 100)

             {

              Size textSize = TextRenderer.MeasureText(g, this.Text, this.Font, rect.Size, textFlags);

              if (textSize.Height <= this.Icon.Height)

              {

              rect.Y += (this.Icon.Height - textSize.Height) / 2;

              }

             }

             }

           

             //g.FillRectangle(Brushes.Gainsboro, rect);//test

           

             //繪制文本

             TextRenderer.DrawText(g, this.Text, this.Font, rect, Color.Black, textFlags);

           

             base.OnPaint(e);

            }

           

            /// <summary>

            /// 根據原尺寸,得到相同面積、且指定比例的新尺寸

            /// </summary>

            /// <param name="src">原尺寸</param>

            /// <param name="scale">新尺寸比例。需是width/height</param>

            private static SizeF GetSameSizeWithNewScale(Size src, float scale)

            {

             int sqr = src.Width * src.Height;//原面積

             double w = Math.Sqrt(sqr * scale);//新面積寬

             return new SizeF(Convert.ToSingle(w), Convert.ToSingle(sqr / w));

            }

           

            /// <summary>

            /// 獲取刨去Padding的內容區

            /// </summary>

            private Rectangle GetPaddedRectangle()

            {

             Rectangle r = this.ClientRectangle;

             r.X += this.Padding.Left;

             r.Y += this.Padding.Top;

             r.Width -= this.Padding.Horizontal;

             r.Height -= this.Padding.Vertical;

             return r;

            }

            }

           

            /// <summary>

            /// 屏蔽全選消息的文本框

            /// </summary>

            private class TextBoxUnSelectAllable : TextBox

            {

            protected override void WndProc(ref Message m)

            {

             //EM_SETSEL

             if (m.Msg == 0xB1) { return; }

           

             base.WndProc(ref m);

            }

            }

           

            /// <summary>

            /// 包裝ToolBarButton為單一控件

            /// </summary>

            private class ToggleButton : Control

            {

            /// <summary>

            /// 展開/收起圖標數據

            /// </summary>

            const string ImgDataBase64 =

          @"iVBORw0KGgoAAAANSUhEUgAAACAAAAAQCAYAAAB3AH1ZAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJ

          bWFnZVJlYWR5ccllPAAAA3NJREFUeNqklVlPFEEQx/8zPccue6gorMd6gBegeCAQD4w+oCx+AInx

          IB4EfTK8+g2MQUUTcBU8En0wmvigEkyMxgcTjRrUqHFVUBRQQaJGl2WPmbG6dzCLWUiESf7T0739

          666urqqVDjVcxT9PAWkfqZKUY491ktpIzaRXGPv5L15J+dZIRx26dqAwf56c48+Cx+1CzDDR//13

          /seevvx3HZ8OxmLxMzSvjhT5Z+Nx8UoKfHOu31e+qWwZPBkOMBkwTAvRuAE21QuvJwNz5s6U25++

          rv365dtC+4SxifJsfeVWvsCJ2TOzqyo2FsHt1OBSFeiqTItIsOhHw7JgGBZM+s72TcOvX+GccHgw

          k7qttgHj5slOLNE0tXZNSQGYJEEhiDEJusLoW4ZMfZnGJVv0QmHhYuiaup+zE+W5Aftyc/xMURRh

          acJIKpowqDVhkhu5LCspiY6k0OIL5s9mdrCNyp9sDKL+6PExeW5AwOebigRNiiVMkoFIPIFwlLcG

          huIm4mRI3DRpAQg38oPMmD6Nuz4wGn+koRGH64/hxr1HuHjl2qg8D8JcZ4ZTRCtLSDjT1Ijz51rS

          5lfVzj2o2rWXXCzDPcnNh3L5K5WntdHYdAqng6cwa/EK+AuK8SDUSx65gUAlxR1ZkcqLLDBpkJ+S

          R8yOvbXw+vx4GOoZsXlZyQqsK10pNlDpjlVZDPMs0FL55mATLl04C39+EWblFf3l2zs+w7jZii1b

          Kkfw3IDOcDiS5/G4yLjknQcCAbrPW3j8plvMWlu8XGwOsblMASYjFh3i3S4SS+W3Vddg++6apJ8t

          OwN4HHH/p+G5AW3f+gbyvB632DwGHigSyjdvpn4b9ElZWF9aJE6uMAanJsOlK3jdNcAXuE2y0vEQ

          rcXfyeCT0vPcES0funoNRTJpgixSRUQsLbapogIbVq8S47rKCORShQvbX7437NI6Km8Ol9sxeG7A

          i2g0Fnz2PAQ3TcjQGBw02UGWOqig8L7bweB1qCSFxHD3/nMMDkWDnJ0oP1yK6z529y1i8ovydaVL

          wXOaXxl3W7K4yKKykY/Rdq8dofe9d+x6jonyw6WYu+Pyj5/hzLedPcU61dDJLh1T3E4BRgYjCHV0

          4/qdJ+bn/h+naW41KZpiwLh5Kc3fMS+vNXaRybVT7YMdcM2228d6/ov/I8AAPfkI7yO+mM8AAAAA

          SUVORK5CYII=";

           

            readonly bool isToggleMode;

            bool isChecked;

            bool useAnimate;

            readonly ImageList imgList;

           

            /// <summary>

            /// Checked改變后

            /// </summary>

            public event EventHandler CheckedChanged;

           

            /// <summary>

            /// 使用動畫按鈕效果

            /// </summary>

            private bool UseAnimate

            {

             get { return useAnimate; }

             set

             {

             if (useAnimate == value) { return; }

           

             useAnimate = value;

             if (IsHandleCreated) { this.CreateHandle(); }

             }

            }

           

            /// <summary>

            /// 獲取或設置按鈕是否處于按下狀態

            /// </summary>

            [Description("獲取或設置按鈕是否處于按下狀態"), DefaultValue(false)]

            public bool Checked

            {

             get

             {

             if (IsHandleCreated)

             {

              //保證isChecked與實情吻合。TB_ISBUTTONCHECKED

              isChecked = Convert.ToBoolean(SendMessage(this.Handle, 0x40A, IntPtr.Zero, IntPtr.Zero).ToInt32());

             }

             return isChecked;

             }

             set

             {

             if (isChecked == value || !isToggleMode) { return; }

           

             isChecked = value;

           

             if (IsHandleCreated)

             {

              //TB_CHECKBUTTON

              SendMessage(this.Handle, 0x402, IntPtr.Zero, new IntPtr(Convert.ToInt32(value)));

             }

           

             OnCheckedChanged(EventArgs.Empty);

             }

            }

           

            /// <summary>

            /// 創建ToolBarButtonControl

            /// </summary>

            public ToggleButton(bool useAnimate)

            {

             SetStyle(ControlStyles.UserPaint, false);

             SetStyle(ControlStyles.AllPaintingInWmPaint, true);

             SetStyle(ControlStyles.OptimizedDoubleBuffer, true);

             SetStyle(ControlStyles.ResizeRedraw, true);

           

             this.isToggleMode = true;//寫死好了,獨立版才提供設置

             this.UseAnimate = useAnimate;

           

             //將圖標加入imageList

             imgList = new ImageList { ImageSize = new System.Drawing.Size(16, 16), ColorDepth = ColorDepth.Depth32Bit };

             using (MemoryStream ms = new MemoryStream(Convert.FromBase64String(ImgDataBase64)))

             {

             imgList.Images.AddStrip(Image.FromStream(ms));

             }

            }

           

            /// <summary>

            /// 執行左鍵單擊

            /// </summary>

            public void PerformClick()

            {

             SendMessage(this.Handle, 0x201, new IntPtr(0x1), IntPtr.Zero);//WM_LBUTTONDOWN

             Application.DoEvents();

             SendMessage(this.Handle, 0x202, IntPtr.Zero, IntPtr.Zero); //WM_LBUTTONUP

            }

           

            protected override void WndProc(ref Message m)

            {

             //忽略鼠標雙擊消息,WM_LBUTTONDBLCLK

             if (m.Msg == 0x203) { return; }

           

             //有節操的響應鼠標動作

             if ((m.Msg == 0x201 || m.Msg == 0x202) && (!this.Enabled || !this.Visible))

             {

             return;

             }

             base.WndProc(ref m);

            }

           

            //創建ToolBar

            protected override CreateParams CreateParams

            {

             get

             {

             CreateParams prms = base.CreateParams;

             prms.ClassName = "ToolbarWindow32";

             prms.Style = 0x40000000

              | 0x10000000

              //| 0x2000000 //WS_CLIPCHILDREN

              //| 0x8000

              | 0x1

              | 0x4

              | 0x8

              | 0x40

              | 0x1000 //TBSTYLE_LIST,圖標文本橫排

              ;

             if (UseAnimate) { prms.Style |= 0x800; }//TBSTYLE_FLAT。flat模式在NT6.x下,按鈕按下會有動畫效果

           

             prms.ExStyle = 0;

           

             return prms;

             }

            }

           

            protected override void OnHandleCreated(EventArgs e)

            {

             base.OnHandleCreated(e);

           

             //設置imgList

             SendMessage(this.Handle, 0x430, IntPtr.Zero, imgList.Handle);//TB_SETIMAGELIST

           

             //準備添加按鈕

             int btnStructSize = Marshal.SizeOf(typeof(TBBUTTON));

             SendMessage(this.Handle, 0x41E, new IntPtr(btnStructSize), IntPtr.Zero);//TB_BUTTONSTRUCTSIZE,必須在添加按鈕前

           

             //構建按鈕信息

             TBBUTTON btnStruct = new TBBUTTON

             {

             //iBitmap = 0,

             //idCommand = 0,

             fsState = 0x4, //TBSTATE_ENABLED

             iString = SendMessage(this.Handle, 0x44D, 0, this.Text + '\0')//TB_ADDSTRING

             };

             if (this.isToggleMode) { btnStruct.fsStyle = 0x2; }//BTNS_CHECK。作為切換按鈕時

           

             IntPtr btnStructStart = IntPtr.Zero;

             try

             {

             btnStructStart = Marshal.AllocHGlobal(btnStructSize);//在非托管區創建一個指針

             Marshal.StructureToPtr(btnStruct, btnStructStart, true);//把結構體塞到上述指針

           

             //添加按鈕

             SendMessage(this.Handle, 0x444, new IntPtr(1)/*按鈕數量*/, btnStructStart);//TB_ADDBUTTONS。從指針取按鈕信息

           

             //設置按鈕尺寸剛好為ToolBar尺寸

             AdjustButtonSize();

             }

             finally

             {

             if (btnStructStart != IntPtr.Zero) { Marshal.FreeHGlobal(btnStructStart); }

             }

            }

           

            protected override bool ProcessCmdKey(ref Message m, Keys keyData)

            {

             //將空格和回車作為鼠標單擊處理

             if (m.Msg == 0x100 && (keyData == Keys.Enter || keyData == Keys.Space))

             {

             PerformClick();

             return true;

             }

           

             return base.ProcessCmdKey(ref m, keyData);

            }

           

            /// <summary>

            /// 處理助記鍵

            /// </summary>

            protected override bool ProcessMnemonic(char charCode)

            {

             if (IsMnemonic(charCode, this.Text))

             {

             PerformClick();

             return true;

             }

           

             return base.ProcessMnemonic(charCode);

            }

           

            protected override void OnClick(EventArgs e)

            {

             //忽略鼠標右鍵

             MouseEventArgs me = e as MouseEventArgs;

             if (me != null && me.Button != System.Windows.Forms.MouseButtons.Left)

             { return; }

           

             //若是切換模式,直接引發Checked事件(不要通過設置Checked屬性引發,因為OnClick發送之前就已經Check了)

             //存在理論上的不可靠,但暫無更好辦法

             if (isToggleMode)

             { this.OnCheckedChanged(EventArgs.Empty); }

           

             base.OnClick(e);

            }

           

            //重繪后重設按鈕尺寸

            protected override void OnInvalidated(InvalidateEventArgs e)

            {

             base.OnInvalidated(e);

             AdjustButtonSize();

            }

           

            /// <summary>

            /// 引發CheckedChanged事件

            /// </summary>

            protected virtual void OnCheckedChanged(EventArgs e)

            {

             SetImageIndex(this.Checked ? 1 : 0);

           

             if (CheckedChanged != null) { CheckedChanged(this, e); }

            }

           

            /// <summary>

            /// 設置圖標索引

            /// </summary>

            private void SetImageIndex(int index)

            {

             //TB_CHANGEBITMAP

             SendMessage(this.Handle, 0x42B, IntPtr.Zero, new IntPtr(index));

            }

           

            /// <summary>

            /// 調整按鈕尺寸剛好為ToolBar尺寸

            /// </summary>

            private void AdjustButtonSize()

            {

             IntPtr lParam = new IntPtr((this.Width & 0xFFFF) | (this.Height << 0x10)); //MakeLParam手法

             SendMessage(this.Handle, 0x41F, IntPtr.Zero, lParam); //TB_SETBUTTONSIZE

            }

           

            #region Win32 API

           

            [DllImport("user32.dll", CharSet = CharSet.Auto)]

            private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);

           

            [DllImport("user32.dll", CharSet = CharSet.Auto)]

            private static extern IntPtr SendMessage(IntPtr hWnd, int msg, int wParam, string lParam);

           

            [StructLayout(LayoutKind.Sequential)]

            private struct TBBUTTON

            {

             public int iBitmap;

             public int idCommand;

             public byte fsState;

             public byte fsStyle;

             public byte bReserved0;

             public byte bReserved1;

             public IntPtr dwData;

             public IntPtr iString;

            }

           

            #endregion

            }

           

            #endregion

           }

           }

          }

          實現說明:

          以下內容獻給童鞋。這里先貼個概要類圖,詳細的后面有完整Demo下載,你可以down回去慢慢研究。

          若干Show方法都是調用私有的ShowCore方法,這個是模仿標準MessageBox的命名。至于意義,是因為公開方法要做參數檢查,檢查合格后的代碼則可以重用。另外,幾個存在參數檢查的方法都是調用內部方法,而不是調參數最全的那個重載,也是因為要盡量避免無謂的參數檢查,因為參數最全的那個公開方法,參數檢查自然是做的最多的,那么少參方法本來已經能確保傳入的是合法參數,卻因為調它,就會造成無謂的檢查,而調內部方法則可以避免,因為內部方法就應該設計為不做或少做參數檢查的。啰嗦這個是想提醒初學者注意這些細節上的處理,性能要從細處抓起

          靜態類MessageBoxEx內部維護著一個MessageForm窗體類(下文簡稱MsgFm),每次Show都會實例化一個MsgFm,show完即釋放。幾乎所有能力都是由后者提供,前者只是簡單的對其封裝和暴露,所以下面主要說MsgFm的事。另外,根據傳入的MessageBoxButtons有無Cancel項,會啟用/屏蔽窗體右上角的關閉按鈕,因為單擊關閉按鈕的對話框結果始終是DialogResult.Cancel,所以如果不屏蔽,在傳入YesNo這樣的參數時候,調用者可能因為用戶去點關閉按鈕而得到Yes、No以外的結果。標準消息框也是有這樣的屏蔽處理的

          MsgFm由3個控件區構成,分別是主消息區、按鈕區、詳細信息區

          主消息區是一個單一控件:MessageViewer,直接繼承自Control寫成。一開始是考慮用現成的Label控件,但發現后者的圖文混排效果差強人意(不要扯這個成語本來的意思),它是把文字直接蓋在圖標上,呵呵,大概此控件的編寫者本意就是要把Image當BackgroundImage用,所以不得已另寫一個MessageViewer。MV主要做了兩個事,繪制(圖標和文本)+根據內容確定自身尺寸,另外它還控制了最小高度,避免圖標和文本整體被淹沒
          按鈕區由一個容器類控件PanelBasic托起4個按鈕。PB同樣是繼承自Control,沒有直接選用Panel的原因,主要是Panel會在設置Dock時跳一下,根源在Control.SetBoundsCore的specified參數通知了無謂的信息,所以干脆直接繼承Control重寫該方法,順便處理一下消息,解決瞬閃的問題,具體原因這里不細說,注釋里有簡短說明,總之相信我不是蛋疼就行了。此外按鈕區會根據按鈕可見情況控制最小寬度,它與上面的MessageViewer的最小高度共同構成了整個對話框的最小尺寸MinimumSize
          PanelBasic上的4個按鈕分別是【詳細信息】按鈕和其它3個對話框命令按鈕。仨按鈕根據傳入的MessageBoxButtons參數動態處理(按鈕文本、是否可見等),沒什么好說的。【詳細信息】按鈕(ToggleButton)則費了番功夫,該按鈕從外觀上就可以看出不是標準的Button,事實上它是個工具欄按鈕:ToolBarButton,屬于ToolBar上的Item,本身不是獨立的控件(直接繼承自Component)。這里扯一點,由于.net 2.0起MS就建議用新式的ToolStrip代替ToolBar,類似的還有MenuStrip代替MainMenu、StatusStrip代替StatusBar、ContextMenuStrip代替ContextMenu,VS2010更是默認就不在工具箱顯示這些“控件”(有些不算控件),所以估計知道的新童鞋不多。后者都是原生的win32組件,前者則是純.net實現的,有Office2003的控件風格。總之對于有win32 native控的我來說,對這些被建議替代的老式控件有特別的情結。所以這個ToggleButton實際上是由一個ToolBar和一個ToolBarButton組成的看起來像一個單一控件的東西,那為什么它還是繼承自Control而不是直接用ToolBar呢,我承認這里面有練手的原因(遲些我可能會寫一篇【教你一步步封裝一個Win32原生控件】的文章),Hmmm~也就這個原因了,但它雖然增加了代碼量,但請務必相信性能不比直接用ToolBar差,理論上還要好過,因為作為一個完備的ToolBar,MS要考慮的情況相當多,顯然處理也少不了,而我這個ToggleButton由于只負責一個單一按鈕的功能,所以其實很Simple很Lite~聰明的你會理解的。最后為什么要費事弄成ToolBarButton而不是直接用一個Button,是因為我看上了mstsc.exe的這個效果:

          順便說一點,EnableAnimate屬性有作用到該按鈕,原理是當ToolBar具有Flat樣式的時候,按鈕按下和彈起就有動畫效果,否則沒有

          最后是詳細信息區,由一個PanelBasic托起一個簡單改造過的TextBox構成。干嘛不單純用一個TextBox,而要在它底下墊一層呢,是因為在XP上的效果不好(控件狗要考慮的情況很多了啦好不好),XP窗口邊框不如NT6粗,不加點襯料的話太單薄。話說回來,PanelBasic上面已說過,而所謂改造過的這個TextBox叫TextBoxUnSelectAllable,就干一件事,忽略全選消息(EM_SETSEL),避免焦點移進去的時候藍瑩瑩一大片嚇到觀眾。而為什么不用標準TextBox的Enter事件取消全選,一個字~太low

          尚存在一個問題,這個注釋里也有坦白,就是當主消息文本非常非常多時~大概整屏那么長(這其實是不正確的使用姿勢,上面說過,大量信息應該放詳細信息區),如果對對話框反復拖拉、展開/收起,那么在某次展開時,TextBoxUnSelectAllable會瞬間在主消息區閃一下,這個問題在PanelBasic得到了完美的解決,但TextBox實在無能為力,嘗試過直接用原生Edit控件也如此,所以暫時留著吧,哪有沒缺憾的人生呢

          關于聲音,由于MessageBeep API在srv08系統無聲,所以用了PlaySound API代替。另外,讓原本沒聲音的MessageBoxIcon.Question蹭SystemIcons.Information的聲音,不能歧視人Question

          最后,【詳細信息】按鈕上那倆圖標(展開、收起各一個)是我畫的,本來想揀mstsc.exe上的,但發現效果不如意,還不如自己畫

          說了這么多,自以為很理想的實現,可能槽點也不少,再次懇請路過大俠指點,謝謝。

          最后,Demo在此,里面有個Tester供你體驗:

          以上就是介紹一款C#中可攜帶附加消息的增強消息框(MessageBoxEx)的詳細內容,更多請關注php中文網其它相關文章!


          百度搜索“就愛閱讀”,專業資料,生活學習,盡在就愛閱讀網92to.com,您的在線圖書館!

          熱點閱讀

          網友最愛

          吉林快三走势图

          <sub id="73hld"><meter id="73hld"></meter></sub><rp id="73hld"><big id="73hld"><listing id="73hld"></listing></big></rp>

            <th id="73hld"><meter id="73hld"><dfn id="73hld"></dfn></meter></th>

              <th id="73hld"></th>
                  <th id="73hld"><form id="73hld"><dfn id="73hld"></dfn></form></th>

                  <sub id="73hld"><meter id="73hld"></meter></sub><rp id="73hld"><big id="73hld"><listing id="73hld"></listing></big></rp>

                    <th id="73hld"><meter id="73hld"><dfn id="73hld"></dfn></meter></th>

                      <th id="73hld"></th>
                          <th id="73hld"><form id="73hld"><dfn id="73hld"></dfn></form></th>