トップ回答者
RectangleShapeを配置したフォームの継承

質問
-
いつもお世話になっております。
C#4.0でWindowsFormアプリケーションを開発しています。
フォームの境界線をオリジナルで実装してほしいと
いう要件があり、RectangleShapeの利用を検討しております。
具体的な要件としては、次の通りです。
・フォームのタイトルバーを非表示にしたい。
・境界線は太い線で表示してほしい。
・境界線の色を指定したい。
この要件を満たすためには、FormのFormBorderStyleをNoneにして
RectangleShapeを配置するのが良いだろうと検討しました。
本対応をするフォームは複数あり、今後も増える予定がありましたので、
本対応をしたフォームをスーパークラスとして用意して、
そのフォームを継承して、それぞれを実装しようと考えました。
しかし、継承すると継承先のフォームのデザイナで
ファイルを開くことができません。
以下の警告が表示されてしまいます。
-----------------------------------------------------------------------------------
サービス System.Windows.Forms.Design.IEventHandlerService は既にサービス コンテナーに存在します。
パラメーター名: serviceType
-----------------------------------------------------------------------------------
警告なのでプログラムは実行でき、
当該フォームも、実行プログラムからは起動できました。
何か手順に問題がありますでしょうか?
RectangleShapeを配置したフォームは継承してはいけないというのが
一般的な規約だったりしますでしょうか?
要件が満たされれば、別な対応策でも良いと考えておりますので、
何か良い方法がございましたら、ご教示頂けますと幸いでございます。
以上、よろしくお願い致します。
回答
-
こんなふうにすれば回避できました
public partial class Form1 : Form { public Form1() { InitializeComponent(); this.Controls.Remove(shapeContainer1); } protected override void OnLoad(EventArgs e) { this.Controls.Add(shapeContainer1); base.OnLoad(e); } //Shapeを貼ったときに自動で作成されるShapeContainer private Microsoft.VisualBasic.PowerPacks.ShapeContainer shapeContainer1; //このフォームを継承したフォームにShapeを貼りたい時は、 //最初だけは一時的にBaseFormにあるShapeContainerを消す必要があるみたい //継承したフォームにShapeを貼らないならこのプロパティは不要 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public virtual bool IsShowBaseShape { get { return _IsShowBaseShape; } set { _IsShowBaseShape = value; if (value) { this.Controls.Add(shapeContainer1); this.Controls.SetChildIndex(shapeContainer1, 0); } else { this.Controls.Remove(shapeContainer1); } } } private bool _IsShowBaseShape = true; }
継承されたフォームがデザイナ用に生成されるときに、ShapeContainerが存在するとエラーを吐くようです。
なので、生成された直後にShapeContainerが存在していないように、一時的にはずしています。また、継承したフォームにShapeを貼ろうとしても、すでにShapeContainerが存在していると*.Designer.csに不完全なコードが生成されてしまいます。
この場合も一時的にShapeContainerをはずしてからShapeを貼ると、正常にコード(新しいShapeContainer)が生成されます。ShapeContainerをpublicやprotectedにするとこの方法でも回避はできないので、privateにしておく必要があります。
個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)
- 回答としてマーク コンドル 2012年11月5日 1:35
すべての返信
-
佐祐理様
デザイナ側のプログラムしか変更されていないので、
そちらを載せますね。
70行くらいになっているので、申し訳ないのですが・・・行っていることとしては、
RectangleShapeをFormに合わせて配置していることと、
FormのFormBorderStyleを変更していることくらいです。namespace WindowsFormsApplication73 { partial class Form1 { /// <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.shapeContainer1 = new Microsoft.VisualBasic.PowerPacks.ShapeContainer(); this.rectangleShape1 = new Microsoft.VisualBasic.PowerPacks.RectangleShape(); this.SuspendLayout(); // // shapeContainer1 // this.shapeContainer1.Location = new System.Drawing.Point(0, 0); this.shapeContainer1.Margin = new System.Windows.Forms.Padding(0); this.shapeContainer1.Name = "shapeContainer1"; this.shapeContainer1.Shapes.AddRange(new Microsoft.VisualBasic.PowerPacks.Shape[] { this.rectangleShape1}); this.shapeContainer1.Size = new System.Drawing.Size(284, 262); this.shapeContainer1.TabIndex = 0; this.shapeContainer1.TabStop = false; // // rectangleShape1 // this.rectangleShape1.BorderWidth = 5; this.rectangleShape1.Location = new System.Drawing.Point(0, 0); this.rectangleShape1.Name = "rectangleShape1"; this.rectangleShape1.Size = new System.Drawing.Size(283, 261); // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(284, 262); this.Controls.Add(this.shapeContainer1); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; this.Name = "Form1"; this.Text = "Form1"; this.ResumeLayout(false); } #endregion private Microsoft.VisualBasic.PowerPacks.ShapeContainer shapeContainer1; private Microsoft.VisualBasic.PowerPacks.RectangleShape rectangleShape1; } }
これをForm2で継承しています。
プログラムは以下の通りです。
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace WindowsFormsApplication73 { public partial class Form2 : Form1 { public Form2() { InitializeComponent(); } } }
既定で作成されているプログラムからは、
「Form」のところをForm1で継承されるよう「Form1」と変更しただけです。何かお分かりになりますでしょうか。
ぜひお願い致します。 -
こんなふうにすれば回避できました
public partial class Form1 : Form { public Form1() { InitializeComponent(); this.Controls.Remove(shapeContainer1); } protected override void OnLoad(EventArgs e) { this.Controls.Add(shapeContainer1); base.OnLoad(e); } //Shapeを貼ったときに自動で作成されるShapeContainer private Microsoft.VisualBasic.PowerPacks.ShapeContainer shapeContainer1; //このフォームを継承したフォームにShapeを貼りたい時は、 //最初だけは一時的にBaseFormにあるShapeContainerを消す必要があるみたい //継承したフォームにShapeを貼らないならこのプロパティは不要 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public virtual bool IsShowBaseShape { get { return _IsShowBaseShape; } set { _IsShowBaseShape = value; if (value) { this.Controls.Add(shapeContainer1); this.Controls.SetChildIndex(shapeContainer1, 0); } else { this.Controls.Remove(shapeContainer1); } } } private bool _IsShowBaseShape = true; }
継承されたフォームがデザイナ用に生成されるときに、ShapeContainerが存在するとエラーを吐くようです。
なので、生成された直後にShapeContainerが存在していないように、一時的にはずしています。また、継承したフォームにShapeを貼ろうとしても、すでにShapeContainerが存在していると*.Designer.csに不完全なコードが生成されてしまいます。
この場合も一時的にShapeContainerをはずしてからShapeを貼ると、正常にコード(新しいShapeContainer)が生成されます。ShapeContainerをpublicやprotectedにするとこの方法でも回避はできないので、privateにしておく必要があります。
個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)
- 回答としてマーク コンドル 2012年11月5日 1:35
-
K. Takaokaさん
gekkaさん
ありがとうございます。
とても参考になりました。
> VB Power Pack は使用していないのですが、エラーメッセージからすると、RectangleShape をデザイナで配置すると、ShapeContainer というのが自動で配置されるのでしょうか?
はい、自動で配置されます。
> それで、ShapeContainer の可視性がデフォルトの private のままになっていて、 protected に変更しないとダメって話だったりしませんかね。
確認してみましたが、解消されませんでした。
確かに!と思ったのですが・・・
表示されていた警告はgekkaさんからご教示頂いた方法で、
解消されました。
shapeContainerの扱いが特殊で、それを考慮する必要があるのですね。
とても勉強になりました。
ありがとうございました。