ユーザーが一度入力した内容を外部の設定ファイルとして保存し、その設定ファイルを読み込んで入力した内容を復元することができればユーザーにとって操作が便利になることがあります。
本記事では、上記仕様をC#のWindowsフォームアプリケーション(.NET Framework)を用いて実装する方法の一例を解説します。
参考例としてプログラムソースを紹介しますが、NameSpaceやクラス名などは除いている箇所があるのでそのまま張り付けるだけでは動かないと思います。また、コントロールの名前の箇所なども適宜修正しながら使っていく必要があります。
(補足)外部ファイルとして保存する他に、AccessやSQLServerなどのデータベースに値を保存する手法も考えられますが、
- ユーザーが利用するにあたりデータベース(Accessの場合はMicrosoft Access Database Engine 2010など)をインストールする手間を省ける
- ユーザーが入力していた値を各コントロールへ戻すだけなので、そのためだけにデータベースを用意する必要はない
などが考えられるので、ユーザーの設定値を保存するためだけにAccessやSQLServerなどを使うまでのことはないと思います。
既に別の用途でAccessやSQLServerなどのデータベースを使っているのであれば、データベースのテーブルに保管する手法も考えられると思います。
サンプルの説明
本記事では下記のような仕様のサンプルを作る方法を紹介していきます。
サンプルの仕様(下図参照)
- アプリケーション起動時、最初にForm1を開く
- Form1の[次の画面へ]ボタンでForm2を表示する。既にForm2を開き各種コントロールの値を変更していた場合はその値を復元する。※次回以降にアプリケーションを起動したときは変更内容は復元されない。
- Form2の[前の画面へ]ボタンでForm1を表示する。既にForm1を開き各種コントロールの値を変更していた場合はその値を復元する。※次回以降にアプリケーションを起動したときは変更内容は復元されない。
- [設定ファイル保存]ボタンで、Form1とForm2に設定されている各種コントロールの値を外部ファイルへ保存する。
- [設定ファイル読み込み]ボタンで、[設定ファイル保存]で保存した外部ファイルを読み込み各種コントロールの値を復元する。
コントロールの設定値を保管する共有クラス
まず、Form1とForm2の値を格納するための共有クラスを作ります。ここではValues.csとします。そして各種コントロールの値を格納するためのプライベート変数とプロパティを用意します。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
namespace Sample
{
static class Values
{
private static string _form1TextBox1 = ""; //Form1のテキストボックス
private static string _form1GroupA = "0"; //Form1のグループボックスA
private static string _form1GroupB = "0"; //Form1のグループボックスB
private static string _form1Check1 = "0"; //Form1チェックボックス
private static string _form1Combobox1 = ""; //Form1コンボボックス
private static string _form2Rhtxt = ""; //Form2のリッチテキストボックス
private static string _form2GroupC = "0"; //Form2のグループボックスC
private static string _form2Check1 = "0"; //Form2チェックボックス
private static string _form2Combobox1 = ""; //Form2コンボボックス
public static string form1TextBox1 { set { _form1TextBox1 = @value; } get { return _form1TextBox1; } }
public static string form1GroupA { set { _form1GroupA = value; } get { return _form1GroupA; } }
public static string form1GroupB { set { _form1GroupB = value; } get { return _form1GroupB; } }
public static string form1Check1 { set { _form1Check1 = value; } get { return _form1Check1; } }
public static string form1Combobox1 { set { _form1Combobox1 = value; } get { return _form1Combobox1; } }
public static string form2Rhtxt { set { _form2Rhtxt = @value; } get { return _form2Rhtxt; } }
public static string form2GroupC { set { _form2GroupC = value; } get { return _form2GroupC; } }
public static string form2Check1 { set { _form2Check1 = value; } get { return _form2Check1; } }
public static string form2Combobox1 { set { _form2Combobox1 = value; } get { return _form2Combobox1; } }
}
}
画面遷移時に各種コントロールの設定値を復元する処理
画面遷移した際に各種コントロールの設定値を復元する処理の作り方を説明します。※次回以降にアプリケーションを起動したときは復元されません。
上記を実装するために、Form1とForm2のそれぞれに
- Valuesクラスの値を各種コントロールへ設定する
- フォームの各種コントロールの値をValuesクラスに保管する
を実装します。ここではこれらの実装方法を解説していきます。
Form1への実装
まずValuesクラスの値を各種コントロールへ設定する処理を実装します。
SetValuesというメソッドでその処理を実装し、画面読み込みイベントでSetValuesメソッドを呼び出すことにします。
※SetValuesの処理は[設定ファイル読み込み]ボタンクリック時の処理でも呼び出します。[設定ファイル読み込み]の実装方法は後ほど解説します。
/// <summary>
/// 画面読み込み時の処理を行います
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Form1_Load(object sender, EventArgs e)
{
SetValues();
}
/// <summary>
/// 変数の値をフォームにセットします
/// </summary>
private void SetValues()
{
//テキストボックスへ値を設定する
this.txt.Text = Values.form1TextBox1;
//ラジオボタンAへ値を設定する
switch (Values.form1GroupA)
{
case "0":
this.rad1.Checked = true;
break;
case "1":
this.rad2.Checked = true;
break;
default:
break;
}
//ラジオボタンBへ値を設定する
switch (Values.form1GroupB)
{
case "0":
this.rad3.Checked = true;
break;
case "1":
this.rad4.Checked = true;
break;
case "2":
this.rad5.Checked = true;
break;
default:
break;
}
//チェックボックスへ値を設定する
if (Values.form1Check1 == "0")
{ this.chk1.Checked = false; }
else
{ this.chk1.Checked = true; }
//コンボボックスへ値を設定する
this.cmb1.Text = Values.form1Combobox1;
}
次にForm1の各種コントロールの値をValuesクラスに保管する処理を実装します。
ReadValuesというメソッドを作り、[次の画面へ]ボタンのクリックイベントでReadValuesメソッドを呼び出すことにします。
※ReadValuesの処理は[設定ファイル保存]ボタンクリック時の処理でも呼び出します。[設定ファイル保存]の実装方法は後ほど解説します。
/// <summary>
/// [次の画面へ]ボタン押下時の処理を行います
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnNext_Click(object sender, EventArgs e)
{
ReadValues();
Form2 f2 = new Form2();
f2.Owner = this;
f2.Show();
this.Visible = false;
}
/// <summary>
/// フォームの値を変数へセットします
/// </summary>
private void ReadValues()
{
Values.form1TextBox1 = txt.Text;
if (rad1.Checked)
{ Values.form1GroupA = "0"; }
else
{ Values.form1GroupA = "1"; }
if (rad3.Checked)
{ Values.form1GroupB = "0"; }
else if (rad4.Checked)
{ Values.form1GroupB = "1"; }
else
{ Values.form1GroupB = "2"; }
if (chk1.Checked)
{ Values.form1Check1 = "1"; }
else
{ Values.form1Check1 = "0"; }
Values.form1Combobox1 = cmb1.Text;
}
Form2への実装
Valuesクラスの値をForm2の各種コントロールへ設定する処置を、画面読み込みイベントに実装します。
/// <summary>
/// 画面読み込み時の処理を行います
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Form2_Load(object sender, EventArgs e)
{
//リッチテキストボックスの値を設定する
this.rhtxt.Text = Values.form2Rhtxt;
//グループボックスCの値を設定する
switch (Values.form2GroupC)
{
case "0":
this.rad1.Checked = true;
break;
case "1":
this.rad2.Checked = true;
break;
default:
break;
}
//チェックボックスの値を設定する
if(Values.form2Check1 == "0")
{ this.chk1.Checked = false; }
else
{ this.chk1.Checked = true; }
//コンボボックスの値を設定する
cmb1.Text = Values.form2Combobox1;
}
次にForm2の各種コントロールの値をValuesクラスに保管する処置を実装します。ReadValuesというメソッドを作り[前の画面へ]ボタンクリックイベントで呼び出すことにします。
※ReadValuesメソッドの処理は[設定ファイル保存]ボタンクリック時の処理でも呼び出します。[設定ファイル保存]の実装方法は後ほど解説します。
/// <summary>
/// [前の画面へ]ボタン押下時の処理を行います
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnPrev_Click(object sender, EventArgs e)
{
ReadValues();
this.Visible = false;
((Form1)this.Owner).Visible = true;
this.Close();
}
/// <summary>
/// フォームにセットされた値を読み込みます。
/// </summary>
private void ReadValues()
{
Values.form2Rhtxt = rhtxt.Text;
if (rad1.Checked)
{ Values.form2GroupC = "0"; }
else
{ Values.form2GroupC = "1"; }
if (chk1.Checked)
{ Values.form2Check1 = "1"; }
else
{ Values.form2Check1 = "0"; }
Values.form2Combobox1 = cmb1.Text;
}
各種コントロールの設定値を設定ファイルへ保存する処理
ここでは、Valuesクラスの値を外部の設定ファイルとして保存する処理を実装します。
設定ファイルのファイル形式は.datとし、設定ファイル内部のフォーマットはコンマ(,)で左からフォーム種別、コントロール種別、コントロールに設定されている値、としています。
また、ファイル保存ダイアログを表示するメソッド(GetFileName)も併せて用意することにします。
/// <summary>
/// ファイル選択ダイアログを表示します
/// </summary>
/// <returns></returns>
public static string GetFileName()
{
SaveFileDialog dataFile = new SaveFileDialog();
dataFile.FileName = "新しいファイル.dat";
dataFile.Filter = "DATファイル(*.dat)|";
if (dataFile.ShowDialog() != DialogResult.OK)
{ return "0"; }
//ファイルダイアログから取得したファイル名の後ろ4文字を確認し、".dat"でなければ".dat"を付け加える。
if (dataFile.FileName.Substring(dataFile.FileName.Length - 4, 4).ToLower() != ".dat")
{ dataFile.FileName += ".dat"; }
return dataFile.FileName;
}
/// <summary>
/// 設定ファイルへの書き込みを行います
/// </summary>
/// <param name="fileName">設定ファイルの絶対パス</param>
public static void WriteFile(string fileName)
{
using (StreamWriter stream = new StreamWriter(fileName, false,Encoding.UTF8))
{
stream.WriteLine("//画面種別,コントロール種別,値, ...");
stream.WriteLine("");
stream.WriteLine("Form1,txt,"+ _form1TextBox1);
stream.WriteLine("Form1,gpb1," + _form1GroupA);
stream.WriteLine("Form1,gpb2," + _form1GroupB);
stream.WriteLine("Form1,chk1," + _form1Check1);
stream.WriteLine("Form1,cmb1," + _form1Combobox1);
using (StringReader richText = new StringReader(_form2Rhtxt))
{
while (richText.Peek() > -1)
{ stream.WriteLine("Form2,rhtxt," + richText.ReadLine()); }
}
stream.WriteLine("Form2,gpb1," + _form2GroupC);
stream.WriteLine("Form2,chk1," + _form2Check1);
stream.WriteLine("Form2,cmb1," + _form2Combobox1);
}
MessageBox.Show("設定ファイルを保存しました。");
}
そして、Form1.csとForm2.csに対し、[設定ファイル保存]ボタンクリック時のイベントとして、上記のメソッド(GetFileNameメソッド、WriteFileメソッド)を呼び出す処理を実装します。
/// <summary>
/// [設定ファイル保存]ボタン押下時の処理を行います
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnSave_Click(object sender, EventArgs e)
{
string fileName = Values.GetFileName();
if (fileName == "0") { return; }
ReadValues();
Values.WriteFile(fileName);
}
/// <summary>
/// [設定ファイル保存]ボタン押下時の処理を行います
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnSave_Click(object sender, EventArgs e)
{
string fileName = Values.GetFileName();
if (fileName == "0"){ return; }
ReadValues();
Values.WriteFile(fileName);
}
設定ファイルの値を読み込む処理
ここでは、各種コントロールの設定値を設定ファイルへ保存する処理で作成した外部ファイルを読み込み、読み込んだ値をValuesクラスに格納する処置を実装します。
設定ファイルを1行ずつ読み込み、コンマ(,)区切りで左端の値が”Form1″または”Form2″の行を処理対象としています。”Form1″、”Form2″それぞれのケースで用いるメソッド(SetValueForm1、SetValueForm2)を用意し、そのメソッドの中でコンマ区切りで左から2つめ以降の値を使いながらValuesクラスに値をセットする処理を行っています。
/// <summary>
/// 設定ファイルの値を各種プライベート変数にセットします
/// </summary>
public static void ReadFile()
{
OpenFileDialog ofdDataFile = new OpenFileDialog();
string readLine = "";
_form2Rhtxt = "";
//設定ファイル選択ダイアログを表示する
ofdDataFile.Filter = "DATファイル(*.dat)|";
if (ofdDataFile.ShowDialog() != DialogResult.OK) { return; }
using (StreamReader dataFile = new StreamReader(ofdDataFile.FileName, Encoding.UTF8))
{
//行数分ループする
while ((readLine = dataFile.ReadLine()) != null)
{
//,区切りで左端の値をチェックし条件分岐
string[] strEle = readLine.Split(',');
switch (strEle[0])
{
case "Form1":
SetValueForm1(strEle);
break;
case "Form2":
SetValueForm2(strEle);
break;
default:
break;
}
}
}
}
/// <summary>
/// Form1の値を変数に格納します
/// </summary>
/// <param name="readValues"></param>
private static void SetValueForm1(string[] readValues)
{
//,区切りで左から2番目の値をチェックし条件分岐する
switch (readValues[1])
{
case "txt":
_form1TextBox1 = readValues[2];
break;
case "gpb1":
_form1GroupA = readValues[2];
break;
case "gpb2":
_form1GroupB = readValues[2];
break;
case "chk1":
_form1Check1 = readValues[2];
break;
case "cmb1":
_form1Combobox1 = readValues[2];
break;
default:
break;
}
}
/// <summary>
/// Form2の値を変数に格納します
/// </summary>
/// <param name="element"></param>
private static void SetValueForm2(string[] element)
{
//,区切りで左から2番目の値をチェックし条件分岐する
switch (element[1])
{
case "rhtxt":
_form2Rhtxt += element[2] + Environment.NewLine;
break;
case "gpb1":
_form2GroupC = element[2];
break;
case "chk1":
_form2Check1 = element[2];
break;
case "cmb1":
_form2Combobox1 = element[2];
break;
default:
break;
}
}
そして、Form1.csの[設定ファイル読み込み]ボタンクリックイベントで、上記ReadFileメソッドを呼び出す処理を記述します。
/// <summary>
/// [設定ファイル読み込み]ボタンを押したときの処理を行います
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnRead_Click(object sender, EventArgs e)
{
Values.ReadFile();
SetValues();
}
その他
Form1、Form2の[終了]ボタンクリック時の処理をそれぞれ記述します。
/// <summary>
/// [終了]ボタン押下時の処理を行います
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnClose_Click(object sender, EventArgs e)
{
this.Close();
}
/// <summary>
/// [終了]ボタン押下時の処理を行います
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnClose_Click(object sender, EventArgs e)
{
Application.Exit();
}
また、Form1、Form2のControlBoxプロパティの値をFalseに設定します。
以上でサンプルの説明で紹介したような仕様になると思います。用途に合わせ適宜修正しながらお使いください。
参考になれば幸いです。