質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

Windows Forms

Windows Forms(WinForms)はMicrosoft .NET フレームワークに含まれる視覚的なアプリケーションのプログラミングインターフェイス(API)です。WinFormsは管理されているコードの既存のWindowsのAPIをラップすることで元のMicrosoft Windowsのインターフェイスのエレメントにアクセスすることができます。

Q&A

解決済

1回答

2828閲覧

C#でのWindowsフォーム作成のイベント処理について

hira_kazu1124

総合スコア9

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

Windows Forms

Windows Forms(WinForms)はMicrosoft .NET フレームワークに含まれる視覚的なアプリケーションのプログラミングインターフェイス(API)です。WinFormsは管理されているコードの既存のWindowsのAPIをラップすることで元のMicrosoft Windowsのインターフェイスのエレメントにアクセスすることができます。

0グッド

1クリップ

投稿2016/08/11 07:06

現在Windows7+VisualStudio+C#の環境でフォームを作成しています。
そこで、少し疑問に思ったことがあったので質問しました。

イベント処理についての質問なのですが、イベントハンドラーが1回でいいのに2回呼ばれたり、呼ばれて欲しくない場面で呼ばれてしまうという問題です。

例えば...

C#

1private void TextBox1_TextChanged(object sender, EventArgs e){ 2 if(TextBox1.Text.SubString(0, 6) != "http//"){ 3 TextBox1.Text = "http//"; //★ 4 } 5}

実際にこんなコードを書いているわけではないですが、こんな処理を書くと、★マークの行を実行した時に、余分にイベントが発生しますよね?
別にこの処理ならそこまで嫌なことはないのですが、重たい処理をしているような場合は2回実行されると少し不満な場合もあります。TextBoxに関してはModified(だったかな?)を使えば回避できるようなことを聞いたことがあり、昔一度成功した記憶もありますが(現在は別の方法で回避しているので、ちょっと忘れかけです^^)。Modifiedの役割も全然理解してません><

今回主に困っているのは、ListViewDataGridViewなどにあるSelectedIndexChangedイベントです(もちろん他のイベントでも共通の悩みはあります)。

SelectedIndexChangedを受け取るイベントハンドラーにSelectedIndexの値をいじる処理を書いてしまうと処理が2回呼ばれてしまいます。また、フォーム開くときの初期化処理で値をセットする場合も、呼ばれて欲しくないタイミングで呼ばれてしまいます。

この問題を回避するために使っている現在の方法は...

C#

1public class EventSwitchForm : Form{ 2 private eventBool = true; 3 4 protected bool EventOn(){ 5 bool before = eventBool; 6 eventBool = true; 7 return before; 8 } 9 10 protected bool EventOff(){ 11 bool before = eventBool; 12 eventBool = false; 13 return before; 14 } 15}

のようなクラスを設計しておき...

C#

1private ListView1_SelectedIndexChanged(object sender, EventArgs e){ 2 if(!EventOff()) return; 3 4 try{ 5 //ここに処理を書く 6 }catch{throw;}finally{EventOn();} 7}

ほぼ全てのイベントハンドラーを上のように書いています。

この方法でも正しく動いているのでとても困っているわけではないのですが、なんとなく原始的ですし、もっとスマートな方法がないかと思っています。イベントハンドラー全てに書き方の規則を設けている時点で人的エラーの元ですし、これから集団で開発する時が来ると嫌われそうな気がしまして...

それとも、このように書かなければ正常に動かないような処理を書いている時点で、あまりよい書き方とは言えないのでしょうか?

このように書かなければ正常に動かない処理の一例としては、一つのデータを二通りの方法で入力させる場合などです。ListViewから選んでも良いし、TextBoxで直に入力しても良い。というような処理の場合...
0. TextBoxに値が入力される

  1. TextBoxのイベントハンドラーが呼ばれる
  2. TextBoxの値に対応する値を検索し、ListViewの適切なアイテムを選択
  3. ListViewのイベントハンドラーが呼ばれる
  4. TextBoxに選択されたアイテムを入力
  5. 2に戻る

1から始めても、4から始めても無限ループになってしまいます。この例の場合は、TextBoxListViewに値をセットするときに前の値と同じかどうか確かめれば良いですが、実際にはもっと複雑な処理を書いているので、その方法が使えないこともあります。

プログラミングに関しては一応10年ほどやっていますが、ほぼ独学です(とはいえ覚えたのは14歳の頃なんで昔はかなり遊びでしたが><)。昔からMacのXcodeを使っていたので、VisualStudioでのWindowsフォーム作成については、あまり大掛かりなものは作ったことがありませんでした(今回が初めてぐらい)。なので結構基本的な分野を見落としている可能性もあります。

長文になってしまい申し訳ないですが、ご教授よろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

データバインドを使いましょう。

投稿2016/08/11 07:33

Zuishin

総合スコア28660

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hira_kazu1124

2016/08/11 07:59

 データバインド! そういえばXcode + Objective-cの時に少し使った記憶が... あまり深く理解せずに使っていたので身についていませんでした^^。  なんとなくコントロールのプロパティとデータを結びつけるようなイメージですが... ListViewの項目とTextBoxのTextをstring型のデータあたりで結びつければ出来るんでしょうかね。TextBoxにあるTextを検索してListViewに適切なSelectedIndexを与えることができれば解決しそうです。  今から調べて勉強してみます^^。  回答ありがとうございました。
Zuishin

2016/08/11 08:48

書いておいてなんですが、ListView そのままではデータバインドは使いにくいので、そこから派生させたクラスを使うか、ListBox や DataGridView 辺りを使うのが楽です。 しかし、どちらにしても UI とデータを切り離せるようデータをバインドする方向で考えて行かれた方がよろしいかと。現状、UI に偏っているのが問題の根源となっている気がします。
hira_kazu1124

2016/08/11 10:00 編集

 現在名簿を管理するようなシステムを書いています。  Personクラスのリストを作り、それぞれのプロパティをListViewに反映し、複数ヘッダでDetail表示させています。選択方法はFullRowSelectはtrueで、MultiSelectはfalseにしています。そして、ListViewで選択されている人(Personクラス)のデータをTextBoxやComboBoxなどで変更させるUIです。  ListView以外の方法は知識不足なのかもしれないです。  ・DataGridViewはFullRowSelectのようなことがやりにくい(自分で描画すれば無理矢理それらしく見えるようにはできますが...)。  ・ListBoxは複数ヘッダに対応していない。  というような感じで捉えています。    単一のプロパティとTextBoxをバインドする処理はなんとか書けました(^^)/ あとは上のような方法を実現するバインド方法がないか調べているところです。  ListViewの選択行とデータを結びつけるイメージだったのですが、「UIとデータを切り離せるよう」ということはそのイメージはあまり良い方法ではないのでしょうか><  「現在選択しているデータ」のクラスを作っておいて、ListViewのSelectedIndexChangedイベントでその「現在選択しているデータ」を更新するイメージの方が正しいのかもしれないですね。  データソースのクラス(バインドするクラス)にリストを格納するイメージでしたが、リストの中身を格納するイメージで処理を考えてみます^^  追伸ありがとうございました^^
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問