C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[1]: ユーザーコントロールのメンバへの参照


(過去ログ 30 を表示中)

[トピック内 22 記事 (1 - 20 表示)]  << 0 | 1 >>

■14561 / inTopicNo.1)  ユーザーコントロールのメンバへの参照
  
□投稿者/ あき (10回)-(2008/02/21(Thu) 17:17:36)

分類:[VB.NET/VB2005] 


ユーザーコントロールを使用した画面を作成しております。

作成したユーザーコントロールをフォームに貼り付けて処理を行いたいのですが、
ユーザーコントロールのメンバ(プロパティ)値を取得するコードで以下のエラーが表示されます。

「非共有メンバを参照するには、オブジェクト参照が必要です。」

ユーザーコントロールの作成方法に問題があるのでしょうか?(共有メンバにするためのSharedが必要なのでしょうか?)
ユーザーコントロールは、VB6.0→VB2005へUpGradeToolを利用して作成したものです。

使用方法の概要は以下の通りです。

@Sub Main
Dim frm As New frm001
frm001.Show()
Application.Run(frm001)


Aフォーム(frm001)上のボタンのクリックイベント
  Dim s As String
s = ユーザーコントロール.プロパティ ※上記のエラーが出ます

以上、よろしくお願い致します。



引用返信 編集キー/
■14563 / inTopicNo.2)  Re[1]: ユーザーコントロールのメンバへの参照
□投稿者/ 魔界の仮面弁士 (645回)-(2008/02/21(Thu) 17:24:38)
No14561 (あき さん) に返信
> s = ユーザーコントロール.プロパティ ※上記のエラーが出ます

実際のソースを見ないとわかりませんが、エラーの内容を見る限り、たとえば、
  s = TextBox1.Text
のように書くべき所で、
  s = TextBox.Text
のように書いているのでは無いでしょうか。
引用返信 編集キー/
■14566 / inTopicNo.3)  Re[2]: ユーザーコントロールのメンバへの参照
□投稿者/ あき (12回)-(2008/02/21(Thu) 18:47:42)
No14563 (魔界の仮面弁士 さん) に返信

このユーザーコントロールは、2つのラベルと1つのテキストボックスからなるコントロールです。
@wStr = Me.UserControl1.CaptionText(実際はラベルのTextプロパティ)
AwStr = Me.UserControl1.Text(テキストのTextプロパティ)
BwStr = Me.UserControl1.NameText(実際はラベルのTextプロパティ)

上記@Bは値を参照できるのですが、Aがうまくいきません。
どうもフォーム上のユーザーコントロールに値を入力しても、参照時には空文字になっています。


実装しているテキストボックス部分のプロパティは以下のようなコードです。
---------------------------------------------------------------------------------
Public Overrides Property Text() As String
Get
Return m_InputText
End Get
Set(ByVal New_Text As String)
If (IsDBNull(New_Text)) And (New_Text.Length = 0) Then
txtText.Text = ""
Else
txtText.Text = New_Text
End If
If New_Text <> m_InputText Then
OnInputTextChanged(EventArgs.Empty)
End If
m_OldText = m_InputText ' 変更前の値を記録
m_InputText = New_Text ' 更新後の値を設定
End Set
End Property
---------------------------------------------------------------------------------

何かお分かりになることはありますでしょうか?
よろしくお願い致します。


引用返信 編集キー/
■14567 / inTopicNo.4)  Re[3]: ユーザーコントロールのメンバへの参照
□投稿者/ Jitta on the way (35回)-(2008/02/21(Thu) 19:50:30)
No14566 (あき さん) に返信
> ■No14563 (魔界の仮面弁士 さん) に返信
>
> このユーザーコントロールは、2つのラベルと1つのテキストボックスからなるコントロールです。
> @wStr = Me.UserControl1.CaptionText(実際はラベルのTextプロパティ)
> AwStr = Me.UserControl1.Text(テキストのTextプロパティ)
> BwStr = Me.UserControl1.NameText(実際はラベルのTextプロパティ)
>
> 上記@Bは値を参照できるのですが、Aがうまくいきません。
> どうもフォーム上のユーザーコントロールに値を入力しても、参照時には空文字になっています。

それは、デバッガで止めて、代入されているか確認してみましたか?



>
>
> 実装しているテキストボックス部分のプロパティは以下のようなコードです。
> ---------------------------------------------------------------------------------
> Public Overrides Property Text() As String
> Get
> Return m_InputText
> End Get
> Set(ByVal New_Text As String)
> If (IsDBNull(New_Text)) And (New_Text.Length = 0) Then

New_TextはStringですよね?DbNullになるのかな?Nothingとの比較じゃないかな?

あと、AndAlsoとElseIfについて調べておくといいと思います。


うん?テキストボックスに、直接書き込んだら(ユーザーアクション)、どうなるんだろう?入らないこと、ないですか?
引用返信 編集キー/
■14568 / inTopicNo.5)  Re[1]: ユーザーコントロールのメンバへの参照
□投稿者/ まどか (451回)-(2008/02/21(Thu) 20:03:32)
#魔界の仮面弁士さんもJittaさんも気づいてないな。。。今のうち

No14561 (あき さん) に返信
> @Sub Main
> Dim frm As New frm001
> frm001.Show()
> Application.Run(frm001)

記述ミスかもしれませんが、frmとfrm001の違いは大丈夫でしょうか?
いわゆる暗黙のフォームインスタンスというやつで、frmのNewしたインスタンスとfrm001.Show()により自動で作成されるインスタンスは別物です。
たぶんコンストラクタによる違いが無いためまったく同じに見えて気付かないだけです。
上記をfrm.Show()とfrm001.Show()の二つにしてみればお分かりになると思います。
したがって正解は
Dim frm As New frm001
Application.Run(frm)
です。
#Runにフォームインスタンスを指定すると自動で表示されます。

引用返信 編集キー/
■14570 / inTopicNo.6)  Re[3]: ユーザーコントロールのメンバへの参照
□投稿者/ 魔界の仮面弁士 (646回)-(2008/02/21(Thu) 20:18:44)
コードを貼る時は、投稿モードを[図表モード]にした方が良いですよ。


■No14566 (あき さん) に返信
……?? 話の流れがわからなくなりました。

これは、最初の質問と同じ内容ですか?
それとも、別の質問ですか?
(別の質問だとしたら、前の問題が解決したのかどうかを教えてください)


> wStr = Me.UserControl1.CaptionText(実際はラベルのTextプロパティ)
> wStr = Me.UserControl1.Text(テキストのTextプロパティ)
> wStr = Me.UserControl1.NameText(実際はラベルのTextプロパティ)

UserControl1 というユーザーコントロールを貼り付けた場合、既定では
UserControl11, UserControl12, UserControl13…という名前になるはずです。

これが、最初の質問と同じなのだとしたら、
 「UserControl1」という「ユーザーコントロールの型名」ではなく、
 フォームに貼りつけた時の「ユーザーコントロールの名前(Name)」
を使ってください。
もし、型名でアクセスしたいのであれば、それらを Shared にする必要があります。



> 上記@Bは値を参照できるのですが、Aがうまくいきません。
UserControl は、もともと「Text プロパティ」を持っています。

もし、元の Text を上書きして、別の Text プロパティを再実装したいなら、
シャドウイングするか、オーバーライドすることになります。
今回は、オーバーライドの道を選択されたのですね?

一応確認。Me.Text と MyClass.Text と MyBase.Text の違いは、把握できていますか?
http://blogs.wankuma.com/jeanne/archive/2006/11/09/44157.aspx
http://smdn.invisiblefulmoon.net/ikimasshoy/vbdotnet/memyclassmybase.html


> どうもフォーム上のユーザーコントロールに値を入力しても、参照時には空文字になっています。
そもそも UserControl の Text プロパティは、非表示扱いになっているはずです。
(プロパティ画面上からも隠されていますし、コードエディタ上でも、IntelliSense に現れないはず)

 Bindable属性 … False
 Browsable属性 … False
 EditorBrowsable属性 … Never
 DesignerSerializationVisibility属性 … Hidden

それでもあえて Text という名前を使おうとしているという事は、
「Overrides Property Text」に対して、これらの属性値を変更しているのでしょうか。
それとも、デザイン時には現れない、隠しプロパティとして実装したいのでしょうか。


もし、属性を変更しているのだとしたら、DesignerSerializationVisibility の内容を
確認してみてください。そして、Form1.Designer.vb ファイルにおいて、Text プロパティの
シリアライズが、期待通りに行われているかを確認してみてください。
デザイナによって空文字列がシリアライズされているなら、起動時の初期値も空になります。


> Get
>    Return m_InputText
> End Get
ここで取得するのは、txtText.Text でも MyBase.Text でもなく「m_InputText」なのですね。
では、この m_InputText の初期値は何にしていますか?


> If (IsDBNull(New_Text)) And (New_Text.Length = 0) Then
New_Text の型は String 型ですよね。

String である以上、IsDBNull は常に False を返します。
ですから、このコードが True になる事はありません。

しかも、(AndAlso ではなく)And 演算子を使っているため、このコードだと、
プロパティに Nothing を代入された場合に、エラーになってしまいます。


>   If New_Text <> m_InputText Then
>       OnInputTextChanged(EventArgs.Empty)
>   End If
>   m_OldText = m_InputText  ' 変更前の値を記録
>   m_InputText = New_Text   ' 更新後の値を設定
ここでは、「m_InputText」が変更される前に、Changed イベントを発生させていますが、
あまり好ましくありません。

Changed というイベント名は、「変更後」に発生させるべきとされていますので、
できれば、m_InputText の変更後に発生させるべきでしょう。

もし、変更前に発生させたいのであれば、Changing という名称にしましょう。


さらに言えば、Text プロパティの変更時に、TextChanged は発生させずに、
InputTextChanged だけを発生させるというのは、対象性が無いような気がします。
プロパティ名とイベント名を統一した方がよろしいかと。

引用返信 編集キー/
■14578 / inTopicNo.7)  Re[4]: ユーザーコントロールのメンバへの参照
□投稿者/ あき (13回)-(2008/02/22(Fri) 10:10:37)
No14570 (魔界の仮面弁士 さん) に返信
> コードを貼る時は、投稿モードを[図表モード]にした方が良いですよ。
 
 すいません。こういった掲示板への投稿が始めてでご迷惑おかけします。
 以後気をつけます。 
  
> これが、最初の質問と同じなのだとしたら、
>  「UserControl1」という「ユーザーコントロールの型名」ではなく、
>  フォームに貼りつけた時の「ユーザーコントロールの名前(Name)」
> を使ってください。
> もし、型名でアクセスしたいのであれば、それらを Shared にする必要があります。
  私の記載表現が悪かったようですね。ユーザーコントロールの名前でアクセスしております。

>>上記@Bは値を参照できるのですが、Aがうまくいきません。
> UserControl は、もともと「Text プロパティ」を持っています。
> 
 もともと持っている「Text プロパティ」はどのようにユーザーコントロール側で
 実装?すれば良いんでしょうか?

> もし、元の Text を上書きして、別の Text プロパティを再実装したいなら、
> シャドウイングするか、オーバーライドすることになります。
> 今回は、オーバーライドの道を選択されたのですね?

  もともと、プロパティ名がTextだったのをInputTextで実装していて、
  最初にご質問したエラーが表示される現象が発生しておりました。

  それを、またTextに変更(アップグレードツールにて生成された状態)に戻した次第です。
 
>>どうもフォーム上のユーザーコントロールに値を入力しても、参照時には空文字になっています。
> そもそも UserControl の Text プロパティは、非表示扱いになっているはずです。
> (プロパティ画面上からも隠されていますし、コードエディタ上でも、IntelliSense に現れないはず)
> 
>  Bindable属性 … False
>  Browsable属性 … False
>  EditorBrowsable属性 … Never
>  DesignerSerializationVisibility属性 … Hidden
> 
> それでもあえて Text という名前を使おうとしているという事は、
> 「Overrides Property Text」に対して、これらの属性値を変更しているのでしょうか。
> それとも、デザイン時には現れない、隠しプロパティとして実装したいのでしょうか。

 デザイナ上から消えてしまうのは、そういう事だったのですね。
 私としては、テキストボックス部分のテキストプロパティを利用できれば良いので
 元々のTextプロパティで十分なのですが、デザイナ上で設定できてコード上からも利用できる
 形にしたいのです。


>>Get
>>   Return m_InputText
>>End Get
> ここで取得するのは、txtText.Text でも MyBase.Text でもなく「m_InputText」なのですね。
> では、この m_InputText の初期値は何にしていますか?
> 
  以下に変更しました。
  Get
     Return txtText.Text
  End Get


>>If (IsDBNull(New_Text)) And (New_Text.Length = 0) Then
> New_Text の型は String 型ですよね。
> 
> String である以上、IsDBNull は常に False を返します。
> ですから、このコードが True になる事はありません。
> 
> しかも、(AndAlso ではなく)And 演算子を使っているため、このコードだと、
> プロパティに Nothing を代入された場合に、エラーになってしまいます。
> 
> 
>>  If New_Text <> m_InputText Then
>>      OnInputTextChanged(EventArgs.Empty)
>>  End If
>>  m_OldText = m_InputText  ' 変更前の値を記録
>>  m_InputText = New_Text   ' 更新後の値を設定
> ここでは、「m_InputText」が変更される前に、Changed イベントを発生させていますが、
> あまり好ましくありません。
> 
> Changed というイベント名は、「変更後」に発生させるべきとされていますので、
> できれば、m_InputText の変更後に発生させるべきでしょう。
> 
> もし、変更前に発生させたいのであれば、Changing という名称にしましょう。
> 
 ご指導ありがとうございます。実装箇所を変更して確認します。
 何か色々問題の箇所がありすぎるようなのでお返事頂いた内容を吟味して整理してみます。
 
  
 

引用返信 編集キー/
■14581 / inTopicNo.8)  Re[5]: ユーザーコントロールのメンバへの参照
□投稿者/ 魔界の仮面弁士 (647回)-(2008/02/22(Fri) 11:33:20)
No14578 (あき さん) に返信
>  もともと持っている「Text プロパティ」はどのようにユーザーコントロール側で
>  実装?すれば良いんでしょうか?
まず、Text プロパティを Overrides します。(現在書かれているコードそのものです)
そして、その「非表示状態」を解除するために、先述の属性を付加します。すなわち

  Imports System.ComponentModel
  <DefaultEvent("TextChanged")> _
  Public Class UserControl1
           :
    <Browsable(True), EditorBrowsable(EditorBrowsableState.Always)> _
    <DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)> _
    Public Overrides Property Text() As String
           :
    End Property
           :
  End Class

のような構造になります。Bindable 属性は変更してもしなくても構いません。
クラスの DefaultEvent 指定も任意です。指定してもしなくても構いません。


> 以下に変更しました。
> Get
>   Return txtText.Text
> End Get
データ保持を txtText に任せるようにしたのですね。

であれば、イベントも繋げて、
  Private Sub txtText_TextChanged(ByVal sender As Object, ByVal e As EventArgs) Handles txtText.TextChanged
    OnTextChanged(EventArgs.Empty)
  End Sub
などとした方が良いかと思います。実行時に、手動で TextBox が編集された場合に備えて。


Set 節については、たとえば、
  Set(ByVal value As String)
    txtText.Text = value
  End Set
といった単純なコードになるかと思います。
ただし、OldText 等の保持が必要であるなら、もう少し異なるコードになるでしょう。
(この部分は、あきさんが書かれている仕様に従ったコードにしてください)


>  もともと、プロパティ名がTextだったのをInputTextで実装していて、
>  最初にご質問したエラーが表示される現象が発生しておりました。
その現象は解決されたのでしょうか?

当方で、「Class UserControl1」に「Public Property IntputText() As String」を
実装して、Form1 に "UserControl1" として貼り付けてみましたが、
  Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
    Me.UserControl11.IntputText = "TEST"
  End Sub
というコードで問題無くコンパイルできましたよ。


>>>If (IsDBNull(New_Text)) And (New_Text.Length = 0) Then
>>しかも、(AndAlso ではなく)And 演算子を使っているため、このコードだと、
>>プロパティに Nothing を代入された場合に、エラーになってしまいます。

この部分、アップグレード前の VB6 ソースはどのようなコードだったのでしょうか?

文字列型である New_Text が、空(Nothing または 長さゼロの文字列)で
あるかどうかを検証したいのであれば、上記のようなコードではなく、
  If Len(New_Text) <> 0 Then
あるいは、
  If New_Text = "" Then
あるいは、
  If New_Text = Nothing Then
あるいは、
  If String.IsNullOrEmpty(New_Text) Then
などと書けば良いかと思います。


元のコードを尊重した書き方にするのであれば、
  If IsNothing(New_Text) OrElse New_Text.Length = 0 Then
あるいは、
  If New_Text Is Nothing OrElse New_Text.Length = 0 Then
などといった表現になるでしょう。
(今回は And / AndAlso ではなく、Or / OrElse を使っています)

引用返信 編集キー/
■14594 / inTopicNo.9)  Re[6]: ユーザーコントロールのメンバへの参照
□投稿者/ あき (14回)-(2008/02/22(Fri) 15:59:12)
No14581 (魔界の仮面弁士 さん) に返信
>もともと持っている「Text プロパティ」はどのようにユーザーコントロール側で
 
  Textプロパティの実装試してみます。

>もともと、プロパティ名がTextだったのをInputTextで実装していて、
>最初にご質問したエラーが表示される現象が発生しておりました。
>その現象は解決されたのでしょうか?

 解消されてはおりません。
 フォーム上のユーザーコントロールの値を、モジュール内から参照すると
 「非共有メンバへのアクセス....」のエラーがでます。

  1.Main関数よりスタートアップフォームの起動
 2.フォームより、Sample.DaatRead様な記述でモジュール内の関数をコール
 3.モジュール内でフォーム上のユーザーコントロールのプロパティを参照

    Modul Sample
    Public Sub DataRead
           Dim s as String = UserCtl.InputText
        End Sub
    End Sample
 
 上記1.のMain関数の中では、ユーザーコントロールを貼り付けているフォームのインスタンスを生成して
 Application.Run(フォーム)の処理を書いています。
 
 VB6.0では実行できる形式のコードです。
 やはりユーザーコントロールに問題があるのでしょうか?

引用返信 編集キー/
■14595 / inTopicNo.10)  Re[7]: ユーザーコントロールのメンバへの参照
□投稿者/ まどか (452回)-(2008/02/22(Fri) 16:34:48)
>  3.モジュール内でフォーム上のユーザーコントロールのプロパティを参照
> 
>     Modul Sample
>     Public Sub DataRead
>            Dim s as String = UserCtl.InputText
>         End Sub
>     End Sample
>  
>  VB6.0では実行できる形式のコードです。

やっぱり、記述ミスではなさそうですね。
先に返信したとおり、「インスタンス」について理解されたほうがよいと思います。

Form1(ボタン1個)とForm2だけの新規プロジェクトで次を実行してみてください。

[Form1]
Private Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Button1.Click

    Dim frmA As New Form2
    frmA.Show()

    Dim frmB As New Form2
    frmB.Show()

    Form2.Show()

    frmA.Text = "frmA"
    frmB.Text = "frmB"
    Form2.Text = "Form2"

End Sub

Form2の部分が暗黙のフォームインスタンスです。
フォームの型名が初めて実行されたときにFrameworkが裏で勝手にNewしてくれます。
それ以降は勝手にそのインスタンスに対してメンバが実行されます。
この仕様はVB6と同じです。
しかし、Newというかインスタンスを意識しないでVB6を使っていらっしゃったので上記の理解ができていないと思われます。

これを踏まえて、
UserCtl.InputText
がどうあるべきかを考えるとよいでしょう。
つまり、「どこの何の」InputTextと書くべきか。

インスタンスがわかったらSharedについて理解をしてください。
「非共有〜」の共有とはSharedだと解釈してください。

引用返信 編集キー/
■14597 / inTopicNo.11)  Re[8]: ユーザーコントロールのメンバへの参照
□投稿者/ あき (15回)-(2008/02/22(Fri) 17:04:15)
No14595 (まどか さん) に返信

  ありがとうございます。
 まどかさんの書いて下さったサンプルコードを実行してみました。
 
 私のコードはつまり、Form2の部分を使用していたことになるという事なのですね。

> それ以降は勝手にそのインスタンスに対してメンバが実行されます。
 この言葉の意味が半分くらいしか理解できません。
 出来ればもう少しどういうことか説明いただきたいのですが。。 

> インスタンスがわかったらSharedについて理解をしてください。
> 「非共有〜」の共有とはSharedだと解釈してください。

 共有メンバにすると、インスタンス生成なしでイキナリクラスのメンバを使用できるという風に理解しております。

 私は、最初のMain関数内でスタートアップフォームのインスタンスを生成してそれを
 Dim frm as New StarUpForm
 Application.Run(frm) とするだけで良いと思っておりました。

 Modulの先頭にも次の記述がいるということでしょうか?

 Public frm as New StartUpForm ※(ユーザーコントロールが貼り付いているフォーム)

  よろしくお願い致します。

引用返信 編集キー/
■14599 / inTopicNo.12)  Re[9]: ユーザーコントロールのメンバへの参照
□投稿者/ 魔界の仮面弁士 (651回)-(2008/02/22(Fri) 17:40:32)
2008/02/22(Fri) 17:42:06 編集(投稿者)
No14597 (あき さん) に返信
> 「非共有メンバへのアクセス....」のエラーがでます。
確認させてください。
UserCtl というのは、「フォームに貼った時につける名前」の方では無く、
「ユーザーコントロールの型名」なのですね?


> 3.モジュール内でフォーム上のユーザーコントロールのプロパティを参照
そもそも、なぜ Module からアクセスさせたいのでしょうか?
StartUpForm 内の事であれば、Module ではなく、StartUpForm 自身にやらせれば良いはず。

どうしても Module に処理させたいのであれば、
 Public Sub DataRead()
  Dim s as String = UserCtl.InputText
 End Sub
ではなく、
 Public Sub DataRead(ByVal ctrl As UserCtl)
  Dim s As String = ctrl.InputText
 End Sub
のように、UserControl のインスタンスを渡してください。
この場合、呼び出し側はスタートアップフォーム内から
 Private Sub StartUpForm_Load(ByVal sender As Object, ……
  DataRead(Me.UserCtl1)
 End Sub
のように書きます。

# このほか、My.Forms.StartUpForm.UserCtl1 や StartUpForm.UserCtl1 の構文を使って
# アクセスする手法もありますが、個人的には、あまりお薦めはしません。


> Modulの先頭にも次の記述がいるということでしょうか?
>  Public frm as New StartUpForm ※(ユーザーコントロールが貼り付いているフォーム)
それではマズイと思いますよ。

「New」した時点で、表示中の物とそっくりの別フォームが新たに生成されて
しまいますので、元のフォームとは別の物を操作する結果になってしまいます。

引用返信 編集キー/
■14600 / inTopicNo.13)  Re[9]: ユーザーコントロールのメンバへの参照
□投稿者/ まどか (453回)-(2008/02/22(Fri) 17:42:06)
>>それ以降は勝手にそのインスタンスに対してメンバが実行されます。
>  出来ればもう少しどういうことか説明いただきたいのですが。。 

たとえば、
Form2.Show()
Form2.Text = "A"
Form2.Hide()
の場合
最初に型名が現れたときにNewされインスタンスが出来上がります。
それ以降の同じ型名は最初に作成されたインスタンスが利用され、「同じインスタンス」が保証されます。
上記を書き直すと
Dim _Form2 As New Form2
_Form2.Show()
_Form2.Text = "A"
_Form2.Hide()
と同じ挙動ということです。
しかも、_Form2は名前空間が一緒ならどこからでもアクセスできます。(どこに書いたForm2.〜もという意味)

よく、このやり方をしないほうがよいといわれる理由は
いったい「いつ」「だれが」作成したインスタンスかわからなくなり、
可読性や保守性、最悪テストのしにくさや動作保証のしにくさにつながるからです。
またこの挙動の欠点は、Newされるタイミングが、「たまたま実行しようとしたときに初めて出てきたから」であり
動作条件によって変わってしまうからです。
#これは「ここではXXXXプロパティが設定されているはずだ」などの前提を作れないことを意味します。
#前提が作れないということは極端な話、テストできないということ

上記のことを踏まえると、すべて暗黙のフォームインスタンスにしてNewされるタイミングを限定して保証するか
すべて明示的にインスタンスを作成し自分が触っているインスタンスがどこの誰が作ったのかを意識するのどちらかです。

>  私は、最初のMain関数内でスタートアップフォームのインスタンスを生成してそれを
>  Dim frm as New StarUpForm
>  Application.Run(frm) とするだけで良いと思っておりました。
> 
>  Modulの先頭にも次の記述がいるということでしょうか?
> 
>  Public frm as New StartUpForm ※(ユーザーコントロールが貼り付いているフォーム)

「Dim frm」はローカル変数ですからMainの中だけで参照できます。
ModuleはNewしなくてもよいクラスと考えてください。
そして、frmとModuleはお互いに階層になっているわけではなくそれぞれが独立して存在します。
つまり、お互いに相手を知りません。
片方を呼び出す場合は呼び出すほうが呼ばれるほうを知っている必要があります。
通常Moduleは「どこからでも呼び出せるユーティリティ」という用途で使います。

ここで考えて欲しいのは、Moduleは呼ばれるほうですからプロジェクト内でもより抽象的な存在になります。
そのModuleが具体的なある特定フォームの特定ユーザーコントロールへアクセスする役割かどうか、です。

べき論を抜きにした解決例は次のようになります。

#Form1にUserControl1がある場合。
#例外の考慮は書いていません。

・暗黙のフォームインスタンスの場合
Dim s as String = Form1.UserControl1.InputText

・インスタンスを意識した場合

Public Shared Sub Main()
    Sample.Form1Instance = New Form1
    Application.Run(Sample.Form1.Instance)
End Sub

Public Module Sample
    Public Form1Instance As Form1
    Public Fuction GetUserControlData() As String
        Dim data As String = Form1Instance.UserContorl1.InputText
        Return data
    End Function
End Module

・インスタンスを意識した場合 その2

呼び出す側がインスタンスを渡してあげる。

Public Module Sample
    Public Fuction GetUserControlData(ByVal ctl As MyUserCtl) As String
        Dim data As String = ctl.InputText
        Return data
    End Function
End Module

例 Dim s As String = Sample.GetUserControlData(Form1Instance.UserControl1)

引用返信 編集キー/
■14602 / inTopicNo.14)  Re[10]: ユーザーコントロールのメンバへの参照
□投稿者/ まどか (454回)-(2008/02/22(Fri) 17:45:48)
訂正です。

> Application.Run(Sample.Form1.Instance)

ではなく

> Application.Run(Sample.Form1Instance)

でした。
引用返信 編集キー/
■14603 / inTopicNo.15)  Re[10]: ユーザーコントロールのメンバへの参照
□投稿者/ あき (16回)-(2008/02/22(Fri) 18:46:00)
No14599 (魔界の仮面弁士 さん) に返信
> 2008/02/22(Fri) 17:42:06 編集(投稿者)
> 
> ■No14597 (あき さん) に返信
>>「非共有メンバへのアクセス....」のエラーがでます。
> 確認させてください。
> UserCtl というのは、「フォームに貼った時につける名前」の方では無く、
> 「ユーザーコントロールの型名」なのですね?
 いえ、フォーム張ったコントロールに対して設定した名前です。

> 
>>3.モジュール内でフォーム上のユーザーコントロールのプロパティを参照
> そもそも、なぜ Module からアクセスさせたいのでしょうか?
> StartUpForm 内の事であれば、Module ではなく、StartUpForm 自身にやらせれば良いはず。
> 
> どうしても Module に処理させたいのであれば、
>  Public Sub DataRead()
>   Dim s as String = UserCtl.InputText
>  End Sub
> ではなく、
>  Public Sub DataRead(ByVal ctrl As UserCtl)
>   Dim s As String = ctrl.InputText
>  End Sub
> のように、UserControl のインスタンスを渡してください。
> この場合、呼び出し側はスタートアップフォーム内から
>  Private Sub StartUpForm_Load(ByVal sender As Object, ……
>   DataRead(Me.UserCtl1)
>  End Sub
> のように書きます。

 Modul内からアクセスしたいのは、元の作りがそうなっているからです。
 呼び出し元からインスタンスを渡す作りに変更しないといけないのですね。
 
>>Modulの先頭にも次の記述がいるということでしょうか?
>> Public frm as New StartUpForm ※(ユーザーコントロールが貼り付いているフォーム)
> それではマズイと思いますよ。
> 
> 「New」した時点で、表示中の物とそっくりの別フォームが新たに生成されて
> しまいますので、元のフォームとは別の物を操作する結果になってしまいます。

 エラーは出なくなったのですが。。。。確かにフォーム上で値を入力したにもかかわらず、
 Textプロパティは空文字になっていました。
 ラベルの値はキチンと保持されているのですが。
 

 
 
 

引用返信 編集キー/
■14605 / inTopicNo.16)  Re[10]: ユーザーコントロールのメンバへの参照
□投稿者/ あき (17回)-(2008/02/22(Fri) 19:12:27)
No14600 (まどか さん) に返信
> >>それ以降は勝手にそのインスタンスに対してメンバが実行されます。
>> 出来ればもう少しどういうことか説明いただきたいのですが。。 
  
  丁寧な解説ありがとうございます。
  魔界の仮面弁士さんにもご指摘いただきましたが、そもそもロジックの設計方法が大きく違うのですね。
  移行ツールでアップグレードした形はあまり信用できないのですかね。

> #Form1にUserControl1がある場合。
> #例外の考慮は書いていません。
>
> ・暗黙のフォームインスタンスの場合
> Dim s as String = Form1.UserControl1.InputText
>
> ・インスタンスを意識した場合
>
> Public Shared Sub Main()
> Sample.Form1Instance = New Form1
> Application.Run(Sample.Form1.Instance)
> End Sub
>
> Public Module Sample
> Public Form1Instance As Form1
> Public Fuction GetUserControlData() As String
> Dim data As String = Form1Instance.UserContorl1.InputText ※
> Return data
> End Function
> End Module
 
上記※印の部分で、フォーム上で入力した値ではなく、空文字が返ってきます。
ちなみに大事な事をお伝えしておりませんでした。Sub Main もModulの中に記述しています。






引用返信 編集キー/
■14606 / inTopicNo.17)  Re[11]: ユーザーコントロールのメンバへの参照
□投稿者/ 魔界の仮面弁士 (652回)-(2008/02/22(Fri) 20:08:40)
No14605 (あき さん) に返信
>   魔界の仮面弁士さんにもご指摘いただきましたが、そもそもロジックの設計方法が大きく違うのですね。
念のために確認なのですが、VB6 ヘルプにある『Visual Basic フォームの有効期間』の
解説を読んだ事はありますか? (その内容を把握できていますか?)


>   移行ツールでアップグレードした形はあまり信用できないのですかね。
それ以前に、そもそも VB6 であったとしても、そのコードはおかしいです。

元のコードが提示されていないので判断が難しいですが、VB6 でも、
モジュール内からコントロールを操作しようとすれば、このような結果になるはず。

'--- VB6 標準モジュール ---
Sub Sample0()
    MsgBox Text1.Text  '★これはエラー★
End Sub
Sub Sample1()
    MsgBox Form1.Text1.Text  'これはOK
End Sub
Sub Sample2(T As TextBox)
    MsgBox T.Text            'これもOK
End Sub
Sub Sample3(F As Form1)
    MsgBox F.Text1.Text      'これもOK
End Sub
Sub Sample4(F As Form)
    MsgBox F.Text1.Text      'これも一応OK (レイトバインド)
End Sub


で、上記でいうところの Sample1 のようなコードで良いなら、手はあります。
No14599 にも少し書きましたが、Module 内からであっても、
 Dim A As String = StartUpForm.TextBox1.Text
 Dim B As String = StartUpForm.UserCtl.InputText
のような表現が可能です。(VB2005以上であれば)

ただしこの方法を使うのであれば、各フォームを New してはいけません。
さらにこの場合、Sub Main プロシージャの表記は、
 Sub Main()
  Application.Run(New StartUpForm())
 End Sub
や
 Sub Main()
  Dim F As New StartUpForm()
  Application.Run(F)
 End Sub
といった表記にする事はできません。
かわりに
 Sub Main()
  Application.Run(StartUpForm)
 End Sub
または
 Sub Main()
  Application.Run(My.Forms.StartUpForm)
 End Sub
と書く必要があります。

引用返信 編集キー/
■14607 / inTopicNo.18)  Re[11]: ユーザーコントロールのメンバへの参照
□投稿者/ まどか (455回)-(2008/02/22(Fri) 20:10:50)
>   移行ツールでアップグレードした形はあまり信用できないのですかね。

極端な話、新しいコンパイラでエラーが無いように新しい書式に変換する、かつ考え方として正しいかより結果が同じになるのが目的
程度に考えておくほうが無難です。
「ツール」ですから。>人間の意図を知ることができない。

>>Public Module Sample
>> Public Sub Main()
>> Sample.Form1Instance = New Form1
>> Application.Run(Sample.Form1.Instance)
>> End Sub
>>
>> Public Form1Instance As Form1
>> Public Fuction GetUserControlData() As String
>> Dim data As String = Form1Instance.UserContorl1.InputText ※
>> Return data
>> End Function
>>End Module

上記でインスタンスの整合性はとれているはずです。
たとえば、Runの直前で「Sample.Form1Instance.Text = "Hoge"」など独自の値を入れて
※でブレークして"Hoge"が設定されているか確認してください。
"Hoge"であれば同じインスタンスを見ていますので上記自体はOKです。
その上でInputTextの値が予期せぬ値であるなら、InputText内のロジックの問題となります。
引用返信 編集キー/
■14608 / inTopicNo.19)  Re[12]: ユーザーコントロールのメンバへの参照
□投稿者/ あき (18回)-(2008/02/22(Fri) 20:41:59)
No14607 (まどか さん) に返信

  ありがとうございます。教えてくださったインスタンスを意識した処理で実装してみます。
  ご報告は来週になると思いますが、また結果を報告します。

>>  移行ツールでアップグレードした形はあまり信用できないのですかね。
>
> 極端な話、新しいコンパイラでエラーが無いように新しい書式に変換する、かつ考え方として正しいかより結果が同じになるのが目的
> 程度に考えておくほうが無難です。
> 「ツール」ですから。>人間の意図を知ることができない。
>
> >>Public Module Sample
> >> Public Sub Main()
> >> Sample.Form1Instance = New Form1
> >> Application.Run(Sample.Form1.Instance)
> >> End Sub
> >>
> >> Public Form1Instance As Form1
> >> Public Fuction GetUserControlData() As String
> >> Dim data As String = Form1Instance.UserContorl1.InputText ※
> >> Return data
> >> End Function
> >>End Module
>
> 上記でインスタンスの整合性はとれているはずです。
> たとえば、Runの直前で「Sample.Form1Instance.Text = "Hoge"」など独自の値を入れて
> ※でブレークして"Hoge"が設定されているか確認してください。
> "Hoge"であれば同じインスタンスを見ていますので上記自体はOKです。
> その上でInputTextの値が予期せぬ値であるなら、InputText内のロジックの問題となります。
引用返信 編集キー/
■14610 / inTopicNo.20)  Re[12]: ユーザーコントロールのメンバへの参照
 
□投稿者/ あき (19回)-(2008/02/22(Fri) 20:52:17)
No14606 (魔界の仮面弁士 さん) に返信

> 元のコードが提示されていないので判断が難しいですが、VB6 でも、
> モジュール内からコントロールを操作しようとすれば、このような結果になるはず。
>
> '--- VB6 標準モジュール ---
> Sub Sample1()
> MsgBox Form1.Text1.Text 'これはOK
> End Sub
 
 私の表現が足りませんでした。VB6のコードは上記のSample1に相当します。
 

> で、上記でいうところの Sample1 のようなコードで良いなら、手はあります。
> No14599 にも少し書きましたが、Module 内からであっても、
>  Dim A As String = StartUpForm.TextBox1.Text
>  Dim B As String = StartUpForm.UserCtl.InputText
> のような表現が可能です。(VB2005以上であれば)
>
> ただしこの方法を使うのであれば、各フォームを New してはいけません。
> かわりに
>  Sub Main()
>   Application.Run(StartUpForm)
>  End Sub
> または
>  Sub Main()
>   Application.Run(My.Forms.StartUpForm)
>  End Sub
> と書く必要があります。

ありがとうございます。上記の記述を試してみます。
ただ今までのお話を聞くと呼び出し元のフォームからインスタンスを引数でモジュールに渡すほうが自然なんですよね?






引用返信 編集キー/

次の20件>
トピック内ページ移動 / << 0 | 1 >>

管理者用

- Child Tree -