C#の質問です

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
taketoshi
記事: 222
登録日時: 15年前
住所: 日本国

C#の質問です

#1

投稿記事 by taketoshi » 13年前

VS2008stdで、フォームアプリケーションを作成し、テキストボックスをForm1上に配置した状態です。
そのテキストボックスからデータを取得し、編集したいと思っています。

Form1クラスから直接データを読みだすには上手く読めるのですが、
別のクラスからもForm1上に配置されているテキストボックスのデータを読み込んでデータを編集したいです。

試しにForm1から派生させてクラス作ってみましたが、別インスタンス?になってしまっているようで、
幾らデータを読み込んでも空白文字しか読み込めませんでした。

C++ですとウインドウハンドルを管理したクラスを作ってstaitc宣言し、
それを継承することでどこからでもコントロールにアクセスできるようにしていたのですが

C#でこういったことをするにはどうしたら良いでしょうか?


以下は幾らやっても空白文字を読んでしまうコードです。

コード:

using System;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        { 
            InitializeComponent();
        }

        //テキストボックスが変更されたときにおこるイベント
        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            //此処でtextBox1も別インスタンスになってる?
            GetStr gs = new GetStr();
            gs.Get();
        }
    }

    //textBox1にアクセスするためにフォーム1を継承したクラス
    //Form1上のテキストボックスからデータを取得して、このクラスで処理を行いたい
    class GetStr : Form1{
        public string str;
        public void Get(){
            //Form1上のtextBox1からデータを取得するにはどうしたらよいか?
            str = textBox1.Text;
        }
    }
}

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: C#の質問です

#2

投稿記事 by softya(ソフト屋) » 13年前

そもそもしないほうが良いと言うのはダメですか?
どうしてもならform1に専用のアクセス用のメソッドを追加すべきです。
ほんとうは、そんな設計にならないのが一番です。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

taketoshi
記事: 222
登録日時: 15年前
住所: 日本国

Re: C#の質問です

#3

投稿記事 by taketoshi » 13年前

そこも踏まえてお尋ねしたかったです。
設計的にForm1内部で済ませ、そもそもしない方が良いのでしょうか・・・?


て、今気が付いたのですが、仰る通りアクセス用のメソッドを作って
読み込んだ変数をクラス間で受け渡した方が早そうですね。

ありがとうございます。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: C#の質問です

#4

投稿記事 by softya(ソフト屋) » 13年前

taketoshi さんが書きました:そこも踏まえてお尋ねしたかったです。
設計的にForm1内部で済ませ、そもそもしない方が良いのでしょうか・・・?


て、今気が付いたのですが、仰る通りアクセス用のメソッドを作って
読み込んだ変数をクラス間で受け渡した方が早そうですね。

ありがとうございます。
form1はテキストボックスも含めてのオブジェクトですから、オブジェクト内で管理するデータを無闇に外部から変更させないのがオブジェクト指向としての基本原則です。
なので、テキストボックス内のデータのことはform1クラスが責任持って管理・加工するべきだと思います。
そういう意味で生のままform1クラスからデータを取り出すのかもform1の責任区分により変わります。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

YuO
記事: 947
登録日時: 15年前
住所: 東京都世田谷区

Re: C#の質問です

#5

投稿記事 by YuO » 13年前

ModelとViewは分離せよ,というGUIの基本的なところに則るなら (e.g. MVC/MVP/PM/MVVM/Doc-View),
  • データや処理を請け負う「Modelオブジェクト」があって,それを「View (=Form)」に渡す
  • Viewは処理をModelに丸投げする
  • ViewはModelの変更をEventを通じて監視する (Observer パターン)
といったところでしょうか。
ObserverパターンのためにEventは.NET Frameworkに組み込まれていますし,
ModelとViewを一致させるためのデータバインド機構は.NET Framework 1.0から存在しています。
# 専らDataGrid系の説明ばっかりなされていすが……。

データバインドを使わないにしても,Formに処理を書くというのは,あまり筋が良いとは思いません。
# 小さいソフトウェアを除く。

taketoshi
記事: 222
登録日時: 15年前
住所: 日本国

Re: C#の質問です

#6

投稿記事 by taketoshi » 13年前

softyaさん返信有難うございます。


もう一点質問があります。ソフトウェアの設計に関する事なのですが
どこでクラスを分ければ(増やせば:継承すれば)良いかという事についてです
例えば以下の状態から public string str; をネットワーク経由で送信する機能を付けたいとします

まだ、C#でデータの送受信とかはやったことないので、やり方については詳しく解らないのですが
データの送受信に関する機能を追加するとなると、どの様な形がベストなのでしょうか

送受信機能をForm1クラスの内部に含めてしまうのか、それとも全くの別クラスとするのか、またはForm1クラスから派生させるのか。
基本的な事をお尋ねしてるの思うのですが、ご教授お願いします。

コード:

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {

        public string str;

        public Form1()
        { 
            InitializeComponent();
        }

        //テキストボックスが変更されたときにおこるイベント
        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            str = textBox1.Text;
        }
    }
}

追加
あぁ、YuOさん書いている間に返信を頂きありがとうございます。
イベントの勉強はしたのですが、まだ完璧に理解できていないので、提示していただいた処理を施すのは少し勉強が必要になりそうです。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: C#の質問です

#7

投稿記事 by softya(ソフト屋) » 13年前

やはり、それとも全くの別クラスとするのが良いと思います。
それはformの役割を超えていますね。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

taketoshi
記事: 222
登録日時: 15年前
住所: 日本国

Re: C#の質問です

#8

投稿記事 by taketoshi » 13年前

ご指導ありがとうございます。


もっとオブジェクト指向プログラムの書き方について慣れていきたいです。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: C#の質問です

#9

投稿記事 by softya(ソフト屋) » 13年前

taketoshi さんが書きました:ご指導ありがとうございます。
もっとオブジェクト指向プログラムの書き方について慣れていきたいです。
YuO さんの推奨されたC#のデスクトップアプリでMVC/MVP/PM/MVVM/Doc-Viewの分かりやすい例は探してみましたが今のところ見つかっておりません。
C#のIDE自体が分かりやすくサポートしてくれていれば問題にならないんですけどね。

あと役割分担ではC言語の構造化プログラミングの手続き/ファイル分割でも役割以上のことをファイル/モジュールがすることは厳禁です。
なので、手続きプログラミングでも何ら変わりませんのでオブジェクト指向かどうかは関係無いんです。
できるだけ低機能の役目を決めたら役目以上のことはさせないってシンプルなルールさえ守れば良いわけで、formは画面の表示と入力だけを受け持つので、それ以外をさせるのはルール違反となるわけです。

【補足】
生活的なところで例を挙げると家電製品で何でもかんでも機能が付いているものは使い勝手が悪かったり、使い回しが難しかったりするわけです。
テレビデオもビデオが故障したらただのテレビに成り下がりますよね。分離できないので使い回しに支障が出る例です。
過去の家電製品で意味不明のものとなるとラジオ付きカメラなんてものがありました。一緒にあって便利でしょうか?って所になると思いますが物が大きくなるし、電池も減るし、重くなるし良くない事だらけです。プログラムも同じ様に見てもらえばよいかと思います。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

YuO
記事: 947
登録日時: 15年前
住所: 東京都世田谷区

Re: C#の質問です

#10

投稿記事 by YuO » 13年前

MVCまわりで長々書きますが,「ModelとViewは分離する」ことが重要です。
ViewにModelが引きずられると,Modelの修正が非常に面倒ですので。
「入力」→「処理」→「出力」という流れであれば,「処理」はView,つまりForm (のコードビハインド) に書かないようにするとよいです。

例示された物だと,「ネットワークに文字列を送信する」処理をFormに書いてはいけません。
# 出来ることの確認等でこねくり回す間はFormでもよいでしょうけれども……。

softya(ソフト屋) さんが書きました:YuO さんの推奨されたC#のデスクトップアプリでMVC/MVP/PM/MVVM/Doc-Viewの分かりやすい例は探してみましたが今のところ見つかっておりません。
えーっと,推奨というより「ModelとViewは分離せよ,というGUIの基本的なところ」の例として出したのですけどね……。
MVCは古典にして全てのはじまりで,
  • View : 表示/Modelの監視者
  • Controller : 入力の受付と入力のModelへの反映
  • Model : ドメインオブジェクト
です。で,MVCのプレゼンテーションロジックを置く場所を考えたら出てきたのがMVPやPM,
PMをWPFやSIlverlght,WinRTに向けて手を入れたのがMVVM,MFCで採用されているMVCの簡易版がDocument-Viewと私は理解しています。
WinFormsを含むMS技術だけではなく,ステートフルなデータを持てる全てのUIを持つアプリケーション (AndroidやiOSなども含まれます) でMVCは基礎知識になります。
# MVCの元祖はSmalltalk。Web系のステートレスMVCは別物 (M/V分離という点では同じですが……) なので注意。

references)
開発者が知っておくべき、6つのUIアーキテクチャ・パターン - @IT
テスト可能なUI設計パターン from テスト可能なUI設計パターン – 第1回 Androidテスト祭り 発表資料 - the sea of fertility
softya(ソフト屋) さんが書きました:C#のIDE自体が分かりやすくサポートしてくれていれば問題にならないんですけどね。
WPF/WinRT用のMVVMの基盤が.NET Frameworkに含まれたり,WPF/WinRT用にMVVMのサポートが追加される可能性はあるでしょうけれども,WinFormsは既にMSのメインの開発対象からは外れていますから難しいでしょうね。
データバインディングとSystem.ComponentModel.INotifyPropertyChangedである程度Model/View分離はできますし。
# ListView/TreeViewなどがバインディング非対応など,WinFormsのバインディング機構はWPFに比べると数段劣りますが。


とりあえず,MとPMとVを分離した (ような) 物 (Presentation Modelベース) を作ってみました。
サンプル (VS2008/C#/.NET 3.5/WinForms)
それぞれ,
  • View→PMはデータバインディング (タイミングはValidating) と通常のメソッド呼び出し
  • PM→ViewはINotifyPropertyChanged.PropertyChangedイベント
    ※PMはViewを知らない
  • PM→Model間は通常のプロパティへのアクセスやメソッド呼び出し
  • Model→PM間は通常のイベント (Updated)
    ※ModelはPMを知らない
で結合しています。
また,データ検証はPMが行い,IDataErrorInfoを経由してViewが拾っています。

役割的には,
  • Form (View) のコードビハインドはForm自身の制御と,PMのメソッド呼び出しを行う
    ※ 薄いView。
  • PMは検証部分主体 (プレゼンテーションロジックがほとんど無いので)。残りはModelに委譲
  • Modelが実際の処理を執り行う
という感じです。
PMのCaluculateメソッドでModelのValue1等に値を設定しているのは,ModelのValue1等の設定時にUpdateが走るように書いていた名残です。
オフトピック
この程度の物だと,面倒なだけですけどね……。
プレゼンテーションロジックがないだけに,PMの意義が薄れてきます。
略式のForm-Modelで作る (ModelのValue1/Value2をテキストボックスにバインドし,button1_ClickでModelのUpdateを直接呼ぶ) としても,ModelとViewの分離が役に立つレベルのプログラムだと,それなりに大規模になってきます。
それもあって,サンプルではそもそもModel/View分離がなされない,という状況なのだと思います。

taketoshi
記事: 222
登録日時: 15年前
住所: 日本国

Re: C#の質問です

#11

投稿記事 by taketoshi » 13年前

ご返答が遅れて申し訳ありません。
お二方アドバイスありがとうございました。

softyaさんの説明文とYuOさんのサンプルソースでかなり理解が進みました。
オブジェクト指向について深く考えすぎていた気もします。
ViewとModelを分離するっていうのは目からうろこです。

サンプルソースまで書いていただいてありがとうございました。

taketoshi
記事: 222
登録日時: 15年前
住所: 日本国

Re: C#の質問です

#12

投稿記事 by taketoshi » 13年前

別に質問があるので教えてください。


YuOさんのサンプルソースでは
エディットボックスから数値を取得している箇所が見当たらないのですが
どこで取得しているのでしょうか?

コード:

string value1 = int.Phase(textBox1.text);
なんてコードがあるんじゃないだろうかと調べてみましたが見つかりませんでした。
データバインディングってコントロールが何かしてるんでしょうか?

YuO
記事: 947
登録日時: 15年前
住所: 東京都世田谷区

Re: C#の質問です

#13

投稿記事 by YuO » 13年前

taketoshi さんが書きました:YuOさんのサンプルソースでは
エディットボックスから数値を取得している箇所が見当たらないのですが
どこで取得しているのでしょうか?
テキストボックスからプロパティへの値の設定は,データバインディングの設定によって行われています。

フォームやコントロールのプロパティを見ると,(DataBindings)という項目があります。
この項目を開くと(詳細)とTextやTagなどが表示されます。
今回の場合は,textBox1 (値1を設定するTextBox) のTextプロパティには,
  • presentationModelBindingSourceのValue1とバインドする
  • データソース更新モードはOnValidation (ほぼフォーカスを失ったタイミングに等しい)
となっています。この場合,
  • textBox1のValidation時にTextプロパティの値をValue1に設定する
  • Value1ChangedイベントまたはINotifyPropertyChanged.PropertyChangedイベントが発生したタイミングで,Value1の値をTextに設定する
という動作です。擬似的にコードで書くならば,

コード:

private void textBox1_Validating (object sender, CancelEventArgs e)
{
    _pm.Value1 = textBox1.Text;
}

private pm1_PropertyChanged (object sender, PropertyChangedEventArgs e)
{
    if (e.PropertyName == "Value1")
    {
        textBox1.Text = pm.Value1;
    }
}
あたりでしょうか。データソース更新モードをOnPropertyChangedに変更すると,

コード:

private void textBox1_TextChanged (object sender, EventArgs e)
{
    _pm.Value1 = textBox1.Text;
}
のようなイメージになります。

数値化は,
  • プロパティのsetの中でTryParseで変換可能であることを確認
  • Calculateの中でInt32.Parseを呼び出して整数化
で行っています。
一応,数値プロパティを直接バインドできますが,データバインディングの本来の目的である,
GUIコントロールの状態とオブジェクトの状態を一致させる,という点に問題が出てしまうので行っていません。
# 非数字を入力するとValidateに失敗するのでCauseValidationがfalseに設定されたコントロール以外にフォーカスを移動できないので,大きく問題になることはないですが。

データバインディングの設定方法の説明がてら,一からプロジェクトを作って設定するまでをキャプチャしてみました。
dixq11426wmv.zip
4:45からバインド設定を行っています。
バインド設定なんてあんまり見ないなぁ,と思って作ってみましたが,とあるコンサルタントのつぶやきにキャプチャつきで書いてありました。 入力エラーを対象に書いてはいますが,データバインドも取り扱っています。


ついでに)バグ修正版
  • Model.cs: Model (int, int)の末尾でUpdateを呼び出すように修正
  • Model.cs: Updatedがフィールドだったのでイベントに修正
  • PresentationModel.cs: Value2プロパティのsetの末尾にRaisePropertyChanged("CanCaluculate");を追加

taketoshi
記事: 222
登録日時: 15年前
住所: 日本国

Re: C#の質問です

#14

投稿記事 by taketoshi » 13年前

>YuOさん

動画までつけていただいてありがとうございます。
プログラミング以外にもテーブルレイアウトコントロールの使い方とか知らないことがいっぱいあって勉強になります。

データバインディングについてもご説明いただきありがとうございます。
C#にはこんな機能があるのかと驚いています。
将来的にデータ処理をするプログラムを書きたいので、役に立ちそうです。ASP.NETの技術なんですね。

教えていただいたことを生かして計算が行えるようなテストプログラムを組んでみます。
ありがとうございます。

閉鎖

“C言語何でも質問掲示板” へ戻る