Question

no title on Sun, 21 May 2017 02:47:26


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プロジェクト


Sponsored



Replies

kenjinote on Sun, 21 May 2017 04:38:26


回答ではないですが、私の環境 (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

no title on Sun, 21 May 2017 12:01:26


検証ありがとうございます。doublebufferedがデフォルトでtrueなのは初耳でした…勉強になります。

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

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

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

Azulean on Sun, 21 May 2017 13:08:11


プロジェクトの参照設定がおかしくなっていないか点検してみてください。
たとえば、自分で自分を参照するようになっているなど。

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

no title on Sun, 21 May 2017 13:42:10


ありがとうございます。
恥ずかしながら、自らを参照する、と言うのはどういう状態のことを指すのでしょうか…?
基本的には新規プロジェクトを作成し最初にクラスを作る、という作業を行っておりますので、参照を変更する作業などは行っておりません…

no title on Sun, 21 May 2017 13:44:00


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

Azulean on Sun, 21 May 2017 14:01:18


恥ずかしながら、自らを参照する、と言うのはどういう状態のことを指すのでしょうか…?
基本的には新規プロジェクトを作成し最初にクラスを作る、という作業を行っておりますので、参照を変更する作業などは行っておりません…

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

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

Azulean on Sun, 21 May 2017 14:07:55


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

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

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

no title on Sun, 21 May 2017 16:28:24


    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に外部からアクセスできますが、継承するとアクセスできなくなるのでしょうか?
初歩的な質問ばかり大変申し訳ありません…

Azulean on Sun, 21 May 2017 21:38:38


そもそもの話になってしまうのですが、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

no title on Mon, 22 May 2017 12:56:32


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

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