none
SplitContainerを継承したユーザーコントロールが利用できない RRS feed

  • 質問

  • DoubleBuffer処理のため、SplitContainerを継承したユーザーフォームを作成しています。

    Public Class Workspace
        Inherits SplitContainer
    
        Public Sub New()
            Me.DoubleBuffered = True
    
        End Sub
    End Class

    上記のクラスを作成しリビルド後、デザイナでフォームに貼り付けようとすると、
    "ツールボックスアイテム'Workspace'の読み込みに失敗しました。アイテムはツールボックスから削除されます。"と表示されます。

    なお継承先をPanelとした場合、正常に使うことはできるのですが、どうやら作成の順番で他のユーザーコントロールも使用できなくなる現象が発生するようです。

    1.Panelの継承クラス→正常に使える
    2.SplitContainerの継承クラス→上記エラー
    3.1のクラスを配置しようとする→上記同様エラー

    調べたところ、対象のCPUにx64を設定する場合、ユーザーコントロールが使えず同様の現象が発生する報告を見つけたのですが、現状全てのプロジェクトでAnyCPUを設定しており、意図的に設定を変更しておりません。

    SplitContainerを継承する場合、何か追記すべき点などあるでしょうか。

    開発環境
    VisualStudio Community 2015
    VB.NET
    WindowsFormプロジェクト

    2017年5月21日 2:47

回答

  • そもそもの話になってしまうのですが、SplitContainer自体はPanel1,2に外部からアクセスできますが、継承するとアクセスできなくなるのでしょうか?
    初歩的な質問ばかり大変申し訳ありません…

    プロパティは参照できるようですが、Handles キーワードで認識できなくなるみたいですね。
    (VB.NET 使いではないので細かい仕様は存じませんが…)

    DesignerSerializationVisibility 属性で Content がそのクラスのレベルで見えないと探してくれないようなので、無理矢理書くなら以下のように既存プロパティを隠蔽しつつ、属性を指定することでしょうか。

    <DesignerSerializationVisibility(DesignerSerializationVisibility.Content)>
    Public Overloads ReadOnly Property Panel1 As Panel
        Get
            Return MyBase.Panel1
        End Get
    End Property
    

    2017年5月21日 21:38
    モデレータ

すべての返信

  • 回答ではないですが、私の環境 (Windows 10 x64 & Visual Studio 2015 Community) で同様の操作を行ってみましたが、再現できませんでした。デザイナーで正しく Workspace を貼り付けることが出来ました。全コードは下記のようにして、プラットフォームを「Any CPU」にしています。

    Public Class Form1
    
    End Class
    
    Public Class Workspace
        Inherits SplitContainer
    
        Public Sub New()
            Me.DoubleBuffered = True
    
        End Sub
    End Class

    コードや構成を変更した際に、ソリューションのクリーンを行うことで現象は変わりませんでしょうか?

    ただ、SplitContainer は デフォルトで DoubleBuffered が True のようですので、この設定のためだけでしたら、継承の必要はないようです。

    参考サイト: http://dobon.net/vb/dotnet/control/doublebuffered.html

    2017年5月21日 4:38
  • 検証ありがとうございます。doublebufferedがデフォルトでtrueなのは初耳でした…勉強になります。

    確かに上記コードの場合、問題なく使用できました。
    自分の場合、worckbenchクラスをform1クラスとは別に用意したのですが、その場合だと再現されるようです。

    ※追記
    新しくプロジェクトを作成すると、問題なく生成できました…
    どうも既存の何かしらと競合してる可能性があるので軽く聞き流してもらえればと思います

    ※追記の追記
    新規プロジェクトで、新しいクラスでWorkbenchクラスを作ると動作しません。
    新規プロジェクトのFormクラスと同じページ内に、新しいWorckbenchクラスを作成すると動作、
    その後、新しいクラスを用意し、Workbench2(内容は同じ)を作成すると動作します。
    別のクラスを最初に作ってしまうと動作しないようです。

    • 編集済み no title 2017年5月21日 12:15
    2017年5月21日 12:01
  • プロジェクトの参照設定がおかしくなっていないか点検してみてください。
    たとえば、自分で自分を参照するようになっているなど。

    時々、ソリューション内のコントロールを配置するときに参照設定がおかしくなることがあるようなので…。

    2017年5月21日 13:08
    モデレータ
  • ありがとうございます。
    恥ずかしながら、自らを参照する、と言うのはどういう状態のことを指すのでしょうか…?
    基本的には新規プロジェクトを作成し最初にクラスを作る、という作業を行っておりますので、参照を変更する作業などは行っておりません…
    2017年5月21日 13:42
  • 追加となりますが、splitcontainerを継承した場合、paintイベントが発生しません。
    既存のコントロールの場合、SplitContainer.Panel1.Paintをハンドルさせることで、Panel1内のペイントイベントを拾えていたのですが、ユーザーコントロールの場合、SplitContainer.Panel1.Paintのような書き方ができません…
    2017年5月21日 13:44
  • 恥ずかしながら、自らを参照する、と言うのはどういう状態のことを指すのでしょうか…?
    基本的には新規プロジェクトを作成し最初にクラスを作る、という作業を行っておりますので、参照を変更する作業などは行っておりません…

    プロジェクトの参照設定を見て、そのプロジェクトと同じ名前がいれば、自分で自分を参照する状態ですので Delete キーで削っておいてください。
    自分で参照設定を操作しなくても、ツールボックスからコントロールを配置した際に誤って追加されることがあります。

    もっとも、これが原因だとは言い切れません。
    ほかの原因があるかもしれないので、参考程度に…。

    2017年5月21日 14:01
    モデレータ
  • 追加となりますが、splitcontainerを継承した場合、paintイベントが発生しません。
    既存のコントロールの場合、SplitContainer.Panel1.Paintをハンドルさせることで、Panel1内のペイントイベントを拾えていたのですが、ユーザーコントロールの場合、SplitContainer.Panel1.Paintのような書き方ができません…

    発生しないのか、書けないのか、どちらですか?
    また、継承と書かれていたり、ユーザーコントロールと書かれていたり、フォームと書かれていたり、混乱を招く用法が見受けられます。ユーザーコントロールやフォームは、既存コントロールの継承とは違うものを指すことが多いのでご留意ください。

    継承であればそのまま書けるような気がします。
    ユーザーコントロールに貼り付けている SplitContainer 内の Panel1 をユーザーコントロールの外から参照したいのであれば、Panel1 を公開するプロパティを自分で作ってください。(その方法は、プロパティ追加の方法を調べましょう)

    2017年5月21日 14:07
    モデレータ
  •     Private Sub SplitContainer1_Paint(sender As Object, e As PaintEventArgs) Handles SplitContainer1.Panel1.Paint
    
        End Sub
    
        Private Sub Workbench1_Paint(sender As Object, e As PaintEventArgs) Handles Workbench1.Panel1.Paint
    
        End Sub
    

    言葉が下手で申し訳ないです…
    通常のコントロールの場合、前者の用にPanel1と書いてペイントイベントを拾うことができるのですが、
    自分が作成したクラスの場合、後者のように書くことができず、ペイントイベントを拾うことができません。

    なおPanelを公開するとのことですが、

        Public Property MainPanel As Panel
            Get
                Return Me.Panel1
            End Get
            Set(value As Panel)
    
            End Set
        End Property

    このような形でパネルコントロールを公開し、上記後者のPanel1の部分をMainPanelと書き換えましたが、エラー(BC31412)が出る状態です…

    そもそもの話になってしまうのですが、SplitContainer自体はPanel1,2に外部からアクセスできますが、継承するとアクセスできなくなるのでしょうか?
    初歩的な質問ばかり大変申し訳ありません…

    2017年5月21日 16:28
  • そもそもの話になってしまうのですが、SplitContainer自体はPanel1,2に外部からアクセスできますが、継承するとアクセスできなくなるのでしょうか?
    初歩的な質問ばかり大変申し訳ありません…

    プロパティは参照できるようですが、Handles キーワードで認識できなくなるみたいですね。
    (VB.NET 使いではないので細かい仕様は存じませんが…)

    DesignerSerializationVisibility 属性で Content がそのクラスのレベルで見えないと探してくれないようなので、無理矢理書くなら以下のように既存プロパティを隠蔽しつつ、属性を指定することでしょうか。

    <DesignerSerializationVisibility(DesignerSerializationVisibility.Content)>
    Public Overloads ReadOnly Property Panel1 As Panel
        Get
            Return MyBase.Panel1
        End Get
    End Property
    

    2017年5月21日 21:38
    モデレータ
  • ここまで長々と説明いただきありがとうございます。
    確かに上記のコードでペイントイベントを拾うことができました。
    継承だけでもコレだけ不便になるんですね…

    自分の理解が全く追いついておらず、利用は少し見送りたいと思いますが、勉強させていただきます。
    シリアライズは初めて使いました…

    2017年5月22日 12:56