はじめに
今回は、
イベントを発生させるクラスを作る
以下は、
using System.ComponentModel;
namespace WindowsFormsApplication1
{
//*************************************************************
/// <summary>値が変わったことを通知するクラスです</summary>
//*************************************************************
class NotifyPropertyChanged : INotifyPropertyChanged
{
//*************************************************************
/// <summary>PropertyChanged イベント</summary>
//*************************************************************
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName) {
if (this.PropertyChanged == null) return;
object sender = this;
PropertyChangedEventArgs e
= new PropertyChangedEventArgs(propertyName);
this.PropertyChanged(sender, e);
}
}
}
インターフェイスの継承
このクラスは、
インターフェイスとは、
public event PropertyChangedEventHandler PropertyChanged;
なお、
イベント発生メソッド
以下は、
protected virtual void OnPropertyChanged(string propertyName) {
if (this.PropertyChanged == null) return;
object sender = this;
PropertyChangedEventArgs e
= new PropertyChangedEventArgs(propertyName);
this.PropertyChanged(sender, e);
}
このメソッドでは、
protectedアクセス修飾子は、
virtualキーワードは、
例えば、
class OverrideSample : NotifyPropertyChanged {
protected override void OnPropertyChanged(string propertyName) {
if (propertyName == "") return;
base.OnPropertyChanged(propertyName);
}
}
これによってOverrideSampleオブジェクトでOnPropertyChangeメソッドを実行すると上記の処理が実行されます。
ロジックのクラスを作る
次に、
すでに、
using System;
namespace WindowsFormsApplication1
{
//*************************************************************
/// <summary>電話帳サンプルコンポーネント</summary>
//*************************************************************
class Logic : NotifyPropertyChanged
{
private Adapter adapter;
//*************************************************************
/// <summary>コンストラクタ</summary>
//*************************************************************
public Logic() {
this.adapter = new Adapter();
}
//*************************************************************
/// <summary>Code プロパティ</summary>
//*************************************************************
private int _Code = 0;
public int Code {
get { return this._Code; }
set {
if (this._Code == value) return;
this._Code = value;
base.OnPropertyChanged("Code");
}
}
//*************************************************************
///<summary>Row プロパティ</summary>
//*************************************************************
private Row _Row = new Row();
public Row Row {
get { return this._Row; }
private set { this._Row = value; }
}
//*************************************************************
/// <summary>追加処理を実行します</summary>
//*************************************************************
public void Add() {
this.InvalidCode();
if (this.adapter.Read(this.Code, this.Row)) {
throw new Exception("既に登録されている番号です");
}
this.adapter.Add(this.Code);
this.Read();
}
//*************************************************************
/// <summary>更新処理を実行します</summary>
//*************************************************************
public void Update() {
this.InvalidCode();
this.adapter.Update(this.Row);
}
//*************************************************************
/// <summary>削除処理を実行します</summary>
//*************************************************************
public void Delete() {
this.InvalidCode();
this.adapter.Delete(this.Code);
this.Code = 0;
this.Row.Clear();
}
//*************************************************************
/// <summary>読込み処理を実行します</summary>
//*************************************************************
public void Read() {
if (!this.adapter.Read(this.Code, this.Row)) {
this.Row.Clear();
throw new Exception("番号が見つかりません");
}
}
//*************************************************************
/// <summary>番号値が有効かどうかを検証した結果を取得します
/// </summary>
//*************************************************************
private void InvalidCode() {
if (this.Code > 0 || this.Code < 100000000) return;
throw new Exception("番号が有効な値ではありません");
}
}
}
クラスの概要
このクラスの持つインターフェイスは、
- イベント
- OnPropertyChanged
(継承元クラスで実装) - プロパティ
- Code、
Row (取得のみで設定は不可) - メソッド
- Add、
Update、 Delete、 Read
つまりはCodeにセットされた値に対して、
Readによって得られた値はRowプロパティによってRowオブジェクトとして提供されます。
また、
例外エラー
前回移植したC#のコードでは、
このクラスでは、
ユーザーインターフェイスのクラスを作る
Form1クラスは、
今までに作成したクラスを使って、
using System;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
//*************************************************************
/// <summary>電話帳サンプルソフトフォーム</summary>
//*************************************************************
public partial class Form1 : Form
{
private Logic logic;
//*************************************************************
///<summary>コンストラクタ</summary>
//*************************************************************
public Form1() {
this.InitializeComponent();
this.logic = new Logic();
this.codeTextBox.DataBindings.Add(
"Text", this.logic, "Code");
this.nameTextBox.DataBindings.Add(
"Text", this.logic.Row, "Name");
this.telephoneNumberTextBox.DataBindings.Add(
"Text", this.logic.Row, "TelephoneNumber");
}
//*************************************************************
// イベント処理用メソッド
//*************************************************************
private void addButton_Click(object sender, EventArgs e) {
try {
this.logic.Add();
}
catch(Exception ex) {
MessageBox.Show(ex.Message);
}
}
private void closeButton_Click(object sender, EventArgs e) {
this.Close();
}
private void readButton_Click(object sender, EventArgs e) {
try {
this.logic.Read();
}
catch(Exception ex) {
MessageBox.Show(ex.Message);
}
}
private void updateButton_Click(object sender, EventArgs e) {
try {
this.logic.Update();
}
catch(Exception ex) {
MessageBox.Show(ex.Message);
}
}
private void deleteButton_Click(object sender, EventArgs e) {
try {
this.logic.Delete();
}
catch(Exception ex) {
MessageBox.Show(ex.Message);
}
}
}
}
上記のコードを眺めることで、
データバインディング
前回移植したコードでは、
しかし、
つまり、
コンストラクタにある以下のコードが、
this.codeTextBox.DataBindings.Add(
"Text", this.logic, "Code");
this.nameTextBox.DataBindings.Add(
"Text", this.logic.Row, "Name");
this.telephoneNumberTextBox.DataBindings.Add(
"Text", this.logic.Row, "TelephoneNumber");
このコードを見て、
詳細についてcodeTextBoxを例にとって順にご説明します。
- 【質問】
codeTextBoxにオブジェクトをバインディングしています。 従って、
自身のオブジェクトのTextプロパティの値が変わったタイミングで、 新しい値をlogicオブジェクトのCodeプロパティに格納することは簡単にできるでしょう。 しかし、
logicオブジェクトのCodeプロパティの値が変わってもcodeTextBoxオブジェクトが知ることができなければ、 常に同じ値に保つことはできません。どうすればよいのでしょうか? - 【回答】
バインディングしたオブジェクトは、
すべてINotifyPropertyChangedインターフェイスを継承し、 プロパティの値が変わるとPropertyChangedイベントが発生します。 このイベントによってcodeTextBoxは、
logicオブジェクトのCodeプロパティの値が変わったことを知り、 自身のTextプロパティの値を設定しなおしています。
つまり、
コマンドの実行
以下は、
try {
this.logic.Add();
}
catch(Exception ex) {
MessageBox.Show(ex.Message);
}
これによって、
発生する例外エラーで渡されるオブジェクトはException型だけではありませんが、
今回作成したクラスダイアグラム
今回作成したクラスダイアグラムは次のようになっています。

次回の予定
前回から2回にわたって、
次回はIDEの機能や既存のクラスを利用した省力化の方法をご紹介します。