コンテキストメニューをインターフェースに合わせて切り替え表示
MyDummySQLProに、ショートカットメニューをつけてみました。
主に、テキストボックスに入っているスクリプトをテンプレートに保存するためのメニュー項目をつけたかったからです。
AccessSavableTextBoxは継承させたかったので、またまたインターフェースでクラス(オブジェクト)を識別認識させています。
IHasCategorizedTextAndContextMenuインターフェースを実装したテキストボックス:TextBoxForTemplate
namespace MyDummySQL.ControlsForTemplate { public class TextBoxForTemplate : AccessSavableTextBox, IHasCategorizedTextAndContextMenu { private string categoryName = "dummy"; public string CategoryName { get { if (this.Parent != null && "dummy".Equals(this.categoryName)) { return this.Parent.Text; } return this.categoryName; } set { this.categoryName = value; } } public TextBoxForTemplate() : base() { this.ContextMenuStrip = (new ContextMenuBuilderFactory()).Create(this).Build(); } public TextBoxForTemplate(string categoryName) : base() { this.categoryName = categoryName; this.ContextMenuStrip = (new ContextMenuBuilderFactory()).Create(this).Build(); } } }
今回インターフェイスは2種あります。
一つ目、ふつうの「コピー」「切り取り」「貼り付け」しかないコンテキストメニューを表示させるテキストボックス用:IHasTextAndContextMenu
namespace MyDummySQL.ControlsForTemplate { public interface IHasTextAndContextMenu { string Text { get; set; } string SelectedText { get; set; } //System.Windows.Forms.ContextMenuStrip ContextMenuStrip { get; set; } } }
二つ目、一つ目のメニューに加えて「テンプレートに保存」「テンプレートから取得」のメニュー項目も表示するテキストボックス用:
namespace MyDummySQL.ControlsForTemplate { public interface IHasCategorizedTextAndContextMenu : IHasTextAndContextMenu { string CategoryName { get; set; } } }
次に、メニューを作成するクラスを、インターフェースで切り替え生成するファクトリ:ContextMenuBuilderFactory
namespace MyDummySQL.ControlsForTemplate { public class ContextMenuBuilderFactory { public ContextMenuBuilderFactory() { } public ContextMenuBuilder Create(IHasTextAndContextMenu control) { return new ContextMenuBuilder(control); } public ContextMenuBuilder Create(IHasCategorizedTextAndContextMenu control) { return new ContextMenuBuilderWidthCategory(control); } } }
次に実際に普通のメニューを作成する”自称ビルダー”(注:ビルダーパターンではないです):ContextMenuBuilder
namespace MyDummySQL.ControlsForTemplate { public class ContextMenuBuilder { //ContextMenu protected ContextMenuStrip cMenu = new ContextMenuStrip(); protected IHasTextAndContextMenu HasText = null; public ContextMenuBuilder(IHasTextAndContextMenu control) { this.HasText = control; } virtual public ContextMenuStrip Build() { //this.HasText = control; /* this.BuildCopy(); this.BuildCut(); this.BuildPaste(); */ this.BuildBasicMenu(); return this.cMenu; } private void BuildBasicMenu() { this.BuildCopy(); this.BuildCut(); this.BuildPaste(); } virtual protected void BuildCopy() { //Copy ToolStripMenuItem mCopy = new ToolStripMenuItem(); mCopy.Text = "コピー(&C)"; mCopy.Click += delegate { if (!string.IsNullOrEmpty(this.HasText.SelectedText)) { Clipboard.SetText(this.HasText.SelectedText); } else if (!string.IsNullOrEmpty(this.HasText.Text)) { Clipboard.SetText(this.HasText.Text); } }; this.cMenu.Items.Add(mCopy); } virtual protected void BuildCut() { //Cut ToolStripMenuItem mCut = new ToolStripMenuItem(); mCut.Text = "切り取り(&X)"; mCut.Click += delegate { if (!string.IsNullOrEmpty(this.HasText.SelectedText)) { Clipboard.SetText(this.HasText.SelectedText); this.HasText.SelectedText = ""; } else if (!string.IsNullOrEmpty(this.HasText.Text)) { Clipboard.SetText(this.HasText.Text); this.HasText.Text = ""; } }; this.cMenu.Items.Add(mCut); } virtual protected void BuildPaste() { //Paste ToolStripMenuItem mPaste = new ToolStripMenuItem(); mPaste.Text = "貼り付け(&V)"; mPaste.Click += delegate { if (!string.IsNullOrEmpty(this.HasText.SelectedText)) { this.HasText.SelectedText = Clipboard.GetText(); } else { this.HasText.Text = Clipboard.GetText(); } }; cMenu.Items.Add(mPaste); } } }
さらに上のクラスを継承して、「テンプレートに保存」「テンプレートから取得」メニューを追加する”自称ビルダー”:ContextMenuBuilder
(ただし、テンプレート保存・取得の実装プログラムはまだ作っていませんので、仮です)
namespace MyDummySQL.ControlsForTemplate { public class ContextMenuBuilderWidthCategory : ContextMenuBuilder { //private IHasCategorizedTextAndContextMenu HasCategorizedText = null; public ContextMenuBuilderWidthCategory(IHasCategorizedTextAndContextMenu control) : base(control) { this.HasText = control; } public override ContextMenuStrip Build() { this.cMenu = base.Build(); BuildAddToTemplate(); BuildGetFromTemplate(); return this.cMenu; } virtual public void BuildAddToTemplate() { //Copy ToolStripMenuItem mToTemp = new ToolStripMenuItem(); mToTemp.Text = "テンプレートに保存(&T)"; mToTemp.Click += delegate { string template = string.Empty; string category = string.Empty; if (!string.IsNullOrEmpty(this.HasText.SelectedText)) { template = this.HasText.SelectedText; } else if (!string.IsNullOrEmpty(this.HasText.Text)) { template = this.HasText.Text; } IHasCategorizedTextAndContextMenu obj = this.HasText as IHasCategorizedTextAndContextMenu; if (obj != null) { category = obj.CategoryName; } frmAddTemplates addFrm = new frmAddTemplates(category, template); addFrm.Show(); }; this.cMenu.Items.Add(mToTemp); } virtual public void BuildGetFromTemplate() { //Copy ToolStripMenuItem mFromTemp = new ToolStripMenuItem(); mFromTemp.Text = "テンプレートから取得(&G)"; mFromTemp.Click += delegate { string template = string.Empty; string category = string.Empty; if (!string.IsNullOrEmpty(this.HasText.SelectedText)) { template = this.HasText.SelectedText; } else if (!string.IsNullOrEmpty(this.HasText.Text)) { template = this.HasText.Text; } IHasCategorizedTextAndContextMenu obj = this.HasText as IHasCategorizedTextAndContextMenu; if (obj != null) { category = obj.CategoryName; } frmTemplates frmTemp = new frmTemplates(); frmTemp.Show(); }; this.cMenu.Items.Add(mFromTemp); } } }
テンプレート関連を扱うフォームは以下のような感じです。
・・・つ、疲れた。また来週〜。
Accessにシリアライズ可能なTextBox, ComboBox, ListBox
シリアライズというと、XMLのような気もしますが、
VB6からAccessに慣れ親しんだおいらには、Accessに設定保存してみたいと思えます。
そこで!作ってみました。
まずは、アクセス保存可能インターフェース:IAccessSavable
namespace MyDummySQL.AccessSavables { interface IAccessSavable { string Ext { get; set; } void Save(DAOContext con, string header); void Load(DAOContext con, string header); void SetExt(string ext_); } }
インターフェースを継承したTextBox:AccessSavableTextBox
namespace MyDummySQL.AccessSavables { public class AccessSavableTextBox : TextBox, IAccessSavable { public string Ext { get; set; } public AccessSavableTextBox() : base() { this.Ext = "ext"; } public void Save(DAOContext con, string header) { string saveText = this.Text; if (char.IsLetter(this.PasswordChar) ) { //暗号化 saveText = CryptHelper.EncryptString(saveText, CryptHelper.cryptseed); } MyDummySQLSettingsSingleton.setValue(con, header, "KEY_" + this.Ext.ToUpper() + "_" + this.Name.ToUpper(), this.Text); } public void Load(DAOContext con, string header) { string loadText = MyDummySQLSettingsSingleton.getStringValue(con, header, "KEY_" + this.Ext.ToUpper() + "_" + this.Name.ToUpper()); if (char.IsLetter(this.PasswordChar) ) { //暗号化 loadText = CryptHelper.DecryptString(loadText, CryptHelper.cryptseed); } this.Text = loadText; } public void SetExt(string ext_) { this.Ext = ext_; } } }
インターフェースを継承したComboBox: AccessSavableComboBox
namespace MyDummySQL.AccessSavables { public class AccessSavableComboBox : ComboBox, IAccessSavable { public string Ext { get; set; } public AccessSavableComboBox() : base() { this.Ext = "ext"; } public void Save(DAOContext con, string header) { string key = "KEY_" + this.Ext.ToUpper() + "_" + this.Name.ToUpper(); string idxkey = "KEY_" + this.Ext.ToUpper() + "_IDX_" + this.Name.ToUpper(); int idx = this.SelectedIndex; //delete MyDummySQLSettingsSingleton.deleteSettings(con, header, key); MyDummySQLSettingsSingleton.deleteSettings(con, header, idxkey); //set Liststrs = new List (); foreach (object o in this.Items) { strs.Add(o.ToString()); } MyDummySQLSettingsSingleton.setStringValues(con, header, key, strs); //save idx MyDummySQLSettingsSingleton.setValue(con, header, key, idx); } public void Load(DAOContext con, string header) { this.Items.Clear(); string key = "KEY_" + this.Ext.ToUpper() + "_" + this.Name.ToUpper(); string idxkey = "KEY_" + this.Ext.ToUpper() + "_IDX_" + this.Name.ToUpper(); //load this.Items.AddRange(MyDummySQLSettingsSingleton.getStringValues(con, header, key).ToArray()); //load idx int idx = 0; MyDummySQLSettingsSingleton.getValue(con, header, key, out idx); if (this.Items.Count > idx) { this.SelectedIndex = idx; } } public void SetExt(string ext_) { this.Ext = ext_; } } }
インターフェースを継承したComboBox: AccessSavableListBox
namespace MyDummySQL.AccessSavables { public class AccessSavableListBox : ListBox, IAccessSavable { public string Ext { get; set; } public AccessSavableListBox() : base() { this.Ext = "ext"; } public void Save(DAOContext con, string header) { string key = "KEY_" + this.Ext.ToUpper() + "_" + this.Name.ToUpper(); string idxkey = "KEY_" + this.Ext.ToUpper() + "_IDX_" + this.Name.ToUpper(); int idx = this.SelectedIndex; //delete MyDummySQLSettingsSingleton.deleteSettings(con, header, key); MyDummySQLSettingsSingleton.deleteSettings(con, header, idxkey); //set Liststrs = new List (); foreach (object o in this.Items) { strs.Add(o.ToString()); } MyDummySQLSettingsSingleton.setStringValues(con, header, key, strs); //save idx MyDummySQLSettingsSingleton.setValue(con, header, key, idx); } public void Load(DAOContext con, string header) { this.Items.Clear(); string key = "KEY_" + this.Ext.ToUpper() + "_" + this.Name.ToUpper(); string idxkey = "KEY_" + this.Ext.ToUpper() + "_IDX_" + this.Name.ToUpper(); //load this.Items.AddRange(MyDummySQLSettingsSingleton.getStringValues(con, header, key).ToArray()); //load idx int idx = 0; MyDummySQLSettingsSingleton.getValue(con, header, key, out idx); if (this.Items.Count > idx) { this.SelectedIndex = idx; } } public void SetExt(string ext_) { this.Ext = ext_; } } }
Accessに設定を保存するヘルパーシングルトン:MyDummySQLSettingsSingleton
namespace MyDummySQL.DAOs { public class MyDummySQLSettingsSingleton { #region //定数 public static string TRUE = "true"; public static string FALSE = "false"; #endregion public class values { public int intValue = 0; public string strgValue = ""; public values(int intvalue, string strgvalue) { this.intValue = intvalue; this.strgValue = strgvalue; } } private static MyDummySQLSettingsSingleton sigleton_ = new MyDummySQLSettingsSingleton(); MyDummySQLSettingsSingleton() { } public MyDummySQLSettingsSingleton getInstance() { return MyDummySQLSettingsSingleton.sigleton_; } public static IListgetHeaderTexts() { List headertexts = new List (); DataTable tbl = null; //DBから読み込む using (DAOContext con = new DAOContext(AccessConstring.SettingConString)) { con.OpenConnection(); MyDummySQLSettingsDAO dao = new MyDummySQLSettingsDAO(con); tbl = dao.selectHeaders(); con.CloseConnection(); } if (tbl != null) { foreach (DataRow row in tbl.Rows) { headertexts.Add(row["HEADERTEXT"].ToString()); } } return headertexts; } public static IList getHeaderTexts(DAOContext con) { List headertexts = new List (); DataTable tbl = null; //DBから読み込む MyDummySQLSettingsDAO dao = new MyDummySQLSettingsDAO(con); tbl = dao.selectHeaders(); if (tbl != null) { foreach (DataRow row in tbl.Rows) { headertexts.Add(row["HEADERTEXT"].ToString()); } } return headertexts; } public static void deleteSettings(string headerText) { //DBから読み込む using (DAOContext con = new DAOContext(AccessConstring.SettingConString)) { con.OpenConnection(); MyDummySQLSettingsDAO dao = new MyDummySQLSettingsDAO(con); dao.deleteSettings(headerText); dao.deleteHeader(headerText); con.CloseConnection(); } } public static void deleteSettings(DAOContext con, string headerText) { //DBから読み込む MyDummySQLSettingsDAO dao = new MyDummySQLSettingsDAO(con); dao.deleteSettings(headerText); dao.deleteHeader(headerText); } public static void getValue(string headerText, string strgKey, out int intValue) { intValue = 0; //DBから読み込む using (DAOContext con = new DAOContext(AccessConstring.SettingConString)) { con.OpenConnection(); MyDummySQLSettingsDAO dao = new MyDummySQLSettingsDAO(con); dao.selectSetting(headerText, strgKey, out intValue); con.CloseConnection(); } } public static void getValue(DAOContext con, string headerText, string strgKey, out int intValue) { intValue = 0; if (con.Connection.State != ConnectionState.Open) return; //DBから読み込む MyDummySQLSettingsDAO dao = new MyDummySQLSettingsDAO(con); dao.selectSetting(headerText, strgKey, out intValue); } public static string getStringValue(string headerText, string strgKey) { string strgValue = ""; //DBから読み込む using (DAOContext con = new DAOContext(AccessConstring.SettingConString)) { con.OpenConnection(); MyDummySQLSettingsDAO dao = new MyDummySQLSettingsDAO(con); dao.selectSetting(headerText, strgKey, out strgValue); con.CloseConnection(); } return strgValue; } public static string getStringValue(DAOContext con, string headerText, string strgKey) { string strgValue = ""; if (con.Connection.State != ConnectionState.Open) return ""; //DBから読み込む MyDummySQLSettingsDAO dao = new MyDummySQLSettingsDAO(con); dao.selectSetting(headerText, strgKey, out strgValue); return strgValue; } public static IList getStringValues(string headerText, string strgKey) { List ret = new List (); DataTable tbl = null; //DBから読み込む using (DAOContext con = new DAOContext(AccessConstring.SettingConString)) { con.OpenConnection(); MyDummySQLSettingsDAO dao = new MyDummySQLSettingsDAO(con); tbl = dao.selectSettingRows(headerText, strgKey); con.CloseConnection(); } if (tbl != null) { foreach (DataRow row in tbl.Rows) { ret.Add(row["TEXTVALUE"].ToString()); } } return ret; } public static IList getStringValues(DAOContext con, string headerText, string strgKey) { List ret = new List (); DataTable tbl = null; if (con.Connection.State != ConnectionState.Open) return ret; //DBから読み込む MyDummySQLSettingsDAO dao = new MyDummySQLSettingsDAO(con); tbl = dao.selectSettingRows(headerText, strgKey); if (tbl != null) { foreach (DataRow row in tbl.Rows) { ret.Add(row["TEXTVALUE"].ToString()); } } return ret; } public static void setStringValues(string headerText, string strgKey, IList strgs) { int no = 1; using (DAOContext con = new DAOContext(AccessConstring.SettingConString)) { con.OpenConnection(); MyDummySQLSettingsDAO dao = new MyDummySQLSettingsDAO(con); dao.deleteSettings(headerText, strgKey); foreach (string strg in strgs) { dao.insertNew(headerText, strgKey, no, strg); no++; } con.CloseConnection(); } } public static void setStringValues(DAOContext con, string headerText, string strgKey, IList strgs) { if (con.Connection.State != ConnectionState.Open) return; int no = 1; MyDummySQLSettingsDAO dao = new MyDummySQLSettingsDAO(con); dao.deleteSettings(headerText, strgKey); foreach (string strg in strgs) { dao.insertNew(headerText, strgKey, no, strg); no++; } } public static void setValue(string headerText, string strgKey, int intValue) { using (DAOContext con = new DAOContext(AccessConstring.SettingConString)) { con.OpenConnection(); MyDummySQLSettingsDAO dao = new MyDummySQLSettingsDAO(con); dao.mergeSettings(headerText, strgKey, intValue); con.CloseConnection(); } } public static void setValue(DAOContext con, string headerText, string strgKey, int intValue) { if (con.Connection.State != ConnectionState.Open) return; MyDummySQLSettingsDAO dao = new MyDummySQLSettingsDAO(con); dao.mergeSettings(headerText, strgKey, intValue); } public static void setValue(string headerText, string strgKey, string strgValue) { using (DAOContext con = new DAOContext(AccessConstring.SettingConString)) { con.OpenConnection(); MyDummySQLSettingsDAO dao = new MyDummySQLSettingsDAO(con); dao.mergeSettings(headerText, strgKey, strgValue); con.CloseConnection(); } } public static void setValue(DAOContext con, string headerText, string strgKey, string strgValue) { if (con.Connection.State != ConnectionState.Open) return; MyDummySQLSettingsDAO dao = new MyDummySQLSettingsDAO(con); dao.mergeSettings(headerText, strgKey, strgValue); } public static bool isExistsHeader(string headerText) { bool ret = false; using (DAOContext con = new DAOContext(AccessConstring.SettingConString)) { con.OpenConnection(); MyDummySQLSettingsDAO dao = new MyDummySQLSettingsDAO(con); ret = dao.isExistsHeader(headerText); con.CloseConnection(); } return ret; } public static bool isExistsHeader(DAOContext con, string headerText) { if (con.Connection.State != ConnectionState.Open) return false; bool ret = false; MyDummySQLSettingsDAO dao = new MyDummySQLSettingsDAO(con); ret = dao.isExistsHeader(headerText); return ret; } public static void MergeHeader(string headerText) { using (DAOContext con = new DAOContext(AccessConstring.SettingConString)) { con.OpenConnection(); MyDummySQLSettingsDAO dao = new MyDummySQLSettingsDAO(con); dao.mergeHeader(headerText); con.CloseConnection(); } } public static void MergeHeader(DAOContext con, string headerText) { if (con.Connection.State != ConnectionState.Open) return; MyDummySQLSettingsDAO dao = new MyDummySQLSettingsDAO(con); dao.mergeHeader(headerText); } public static void deleteSettings(string headerText, string strgKey) { using (DAOContext con = new DAOContext(AccessConstring.SettingConString)) { con.OpenConnection(); MyDummySQLSettingsDAO dao = new MyDummySQLSettingsDAO(con); dao.deleteSettings(headerText, strgKey); con.CloseConnection(); } } public static void deleteSettings(DAOContext con, string headerText, string strgKey) { if (con.Connection.State != ConnectionState.Open) return; MyDummySQLSettingsDAO dao = new MyDummySQLSettingsDAO(con); dao.deleteSettings(headerText, strgKey); } } }
Accessに設定を保存するDAO:MyDummySQLSettingsDAO
namespace MyDummySQL.DAOs { class MyDummySQLSettingsDAO : MyDAOBase { public MyDummySQLSettingsDAO(DAOContext con) : base(con) { } #region //SELECT public void selectSetting(string headerText, string strgKey, out int intValue) { string sql = @"select * from settings where SETTINGKEY like @pkey and HEADERTEXT like @pheader"; this.ClearParameters(); this.AddParameter("pkey", DbType.String, strgKey); this.AddParameter("pheader", DbType.String, headerText); DataTable tbl = base.GetTable(sql); if (tbl.Rows.Count > 0) { int ret = 0; int.TryParse(tbl.Rows[0]["INTVALUE"].ToString(), out ret); intValue = ret; } else { intValue = 0; } } public DataRow selectSetting1Row(string headerText, string strgKey) { string sql = @"select * from settings where SETTINGKEY like @pkey and HEADERTEXT like @pheader"; this.ClearParameters(); this.AddParameter("pkey", DbType.String, strgKey); this.AddParameter("pheader", DbType.String, headerText); DataTable tbl = base.GetTable(sql); if (tbl.Rows.Count > 0) { return tbl.Rows[0]; } else { return null; } } public DataTable selectSettingRows(string headeText, string strgKey) { string sql = @"select * from settings where SETTINGKEY like @pkey and HEADERTEXT like @pheader order by NO1 "; this.ClearParameters(); this.AddParameter("pkey", DbType.String, strgKey); this.AddParameter("pheader", DbType.String, headeText); return base.GetTable(sql); } public void selectSetting(string headerText, string strgKey, out string strgValue) { string sql = @"select * from settings where SETTINGKEY like @pkey and HEADERTEXT like @pheader"; this.ClearParameters(); this.AddParameter("pkey", DbType.String, strgKey); this.AddParameter("pheader", DbType.String, headerText); DataTable tbl = base.GetTable(sql); if (tbl.Rows.Count > 0) { strgValue = tbl.Rows[0]["TEXTVALUE"].ToString(); } else { strgValue = ""; } } public DataTable selectHeaders() { string sql = @"select * from header order by HEADERTEXT "; this.ClearParameters(); return base.GetTable(sql); } public bool isExistSetting(string headerText, string strgKey) { string sql = @"select * from settings where SETTINGKEY like @pkey and HEADERTEXT = @pheader"; this.ClearParameters(); this.AddParameter("pkey", DbType.String, strgKey); this.AddParameter("pheader", DbType.String, headerText); DataTable tbl = base.GetTable(sql); if (tbl.Rows.Count > 0) { return true; } else { return false; } } #endregion #region //ヘッダーマージ public bool isExistsHeader(string headerText) { string sql = @"select * from header where HEADERTEXT like @pheader "; this.ClearParameters(); this.AddParameter("pheader", DbType.String, headerText); DataTable tbl = base.GetTable(sql); if (tbl.Rows.Count > 0) { return true; } else { return false; } } public int insertNewHeader(string headerText) { string sql = @"insert into header( HEADERTEXT ) values( @pheader )"; this.ClearParameters(); this.AddParameter("pheader", DbType.String, headerText); return base.ExecuteNonQuery(sql); } public int mergeHeader(string headerText) { if (this.isExistsHeader(headerText)) { return 0; } else { return this.insertNewHeader(headerText); } } #endregion #region //数値設定 public int updateDate(string headerText, string strgKey, int intValue) { string sql = @"update settings set INTVALUE = @pintvalue where SETTINGKEY like @pkey and HEADERTEXT like @pheader"; this.ClearParameters(); this.AddParameter("pintvalue", DbType.Int32, intValue); this.AddParameter("pkey", DbType.String, strgKey); this.AddParameter("pheader", DbType.String, headerText); return base.ExecuteNonQuery(sql); } public int insertNew(string headerText, string strgKey, int intValue) { string sql = @"insert into settings( HEADERTEXT ,NO1 ,SETTINGKEY ,INTVALUE ) values( @pheader ,0 ,@pkey ,@pintvalue )"; this.ClearParameters(); this.AddParameter("pheader", DbType.String, headerText); this.AddParameter("pkey", DbType.String, strgKey); this.AddParameter("pintvalue", DbType.Int32, intValue); return base.ExecuteNonQuery(sql); } public int mergeSettings(string headerText, string strgKey, int intValue) { if (this.isExistSetting(headerText, strgKey)) { return this.updateDate(headerText, strgKey, intValue); } else { return this.insertNew(headerText, strgKey, intValue); } } #endregion #region //数値設定(複数行) public int insertNew(string headerText, string strgKey, int no, int intValue) { string sql = @"insert into settings( HEADERTEXT ,NO1 ,SETTINGKEY ,INTVALUE ) values( @pheader ,@pno ,@pkey ,@pintvalue )"; this.ClearParameters(); this.AddParameter("pheader", DbType.String, headerText); this.AddParameter("pno", DbType.Int32, no); this.AddParameter("pkey", DbType.String, strgKey); this.AddParameter("pintvalue", DbType.Int32, intValue); return base.ExecuteNonQuery(sql); } #endregion #region //文字設定 public int updateDate(string headerText, string strgKey, string strgValue) { string sql = @"update settings set TEXTVALUE = @ptextvalue where SETTINGKEY like @pkey and HEADERTEXT like @pheader"; this.ClearParameters(); this.AddParameter("ptextvalue", DbType.String, strgValue); this.AddParameter("pkey", DbType.String, strgKey); this.AddParameter("pheader", DbType.String, headerText); return base.ExecuteNonQuery(sql); } public int insertNew(string headerText, string strgKey, string strgValue) { string sql = @" insert into settings( HEADERTEXT ,NO1 ,SETTINGKEY ,TEXTVALUE ) values( @pheader1 ,0 ,@pkey1 ,@ptextvalue1 )"; this.ClearParameters(); this.AddParameter("pheader1", DbType.String, headerText); this.AddParameter("pkey1", DbType.String, strgKey); this.AddParameter("ptextvalue1", DbType.String, strgValue); return base.ExecuteNonQuery(sql); } public int mergeSettings(string headerText, string strgKey, string strgValue) { if (this.isExistSetting(headerText, strgKey)) { return this.updateDate(headerText, strgKey, strgValue); } else { return this.insertNew(headerText, strgKey, strgValue); } } #endregion #region //文字設定(複数行) public int insertNew(string headerText, string strgKey, int no, string strgValue) { string sql = @"insert into settings( HEADERTEXT ,NO1 ,SETTINGKEY ,TEXTVALUE ) values( @pheader ,@pno ,@pkey ,@ptextvalue )"; this.ClearParameters(); this.AddParameter("pheader", DbType.String, headerText); this.AddParameter("pno", DbType.Int32, no); this.AddParameter("pkey", DbType.String, strgKey); this.AddParameter("ptextvalue", DbType.String, strgValue); return base.ExecuteNonQuery(sql); } #endregion #region //設定削除(複数行用) public int deleteSettings(string headerText, string strgKey) { string sql = @"delete from settings where SETTINGKEY like @pkey and HEADERTEXT like @pheader"; this.ClearParameters(); this.AddParameter("pkey", DbType.String, strgKey); this.AddParameter("pheader", DbType.String, headerText); return base.ExecuteNonQuery(sql); } public int deleteSettings(string headerText) { string sql = @"delete from settings where HEADERTEXT like @pheader"; this.ClearParameters(); this.AddParameter("pheader", DbType.String, headerText); return base.ExecuteNonQuery(sql); } public int deleteHeader(string headerText) { string sql = @"delete from header where HEADERTEXT like @pheader"; this.ClearParameters(); this.AddParameter("pheader", DbType.String, headerText); return base.ExecuteNonQuery(sql); } #endregion } }
で、実際に保存するまえに、LINQの拡張メソッドで、セーブ可能なコンポーネントをListに登録しておきます。
private ListSavables = new List (); public void init() { foreach (TabPage tab in this.tabCtrlScripts.TabPages) { //regist ↓タブコントロール配下のコントロールを一括登録 this.Savables.AddRange(tab.Controls.OfType ()); //set ext foreach (IAccessSavable savable in tab.Controls.OfType ()) { savable.Ext = this.Name.ToUpper(); } } }
で、実際のセーブとロード用メソッド。
(コネクションプーリングを前提にしています)
public void Save(DAOContext con, string header) { foreach (IAccessSavable savable in this.Savables) { savable.Save(con, header); } } public void Load(DAOContext con, string header) { foreach (IAccessSavable savable in this.Savables) { savable.Load(con, header); } }
で、実際にメイン関数に書くのは、以下。
(カスタムコントロールを書いていますが、そのLoad()、Save()メソッドで、上のSave()、Load()メソッドを呼ぶという形です)
//Load using (DAOContext con = new DAOContext(AccessConstring.SettingConString)) { con.OpenConnection(); this.tabCustControl1.Load(con, header); con.CloseConnection(); }
//Save using (DAOContext con = new DAOContext(AccessConstring.SettingConString)) { con.OpenConnection(); this.tabCustControl1.Save(con, header); con.CloseConnection(); }
ソート可能なデータソース
テキトーなカスタムクラスのデータソースクラス作ったら、グリッドでソートできなかったので、調べてみました。
http://codezine.jp/article/detail/1159?p=2
さすがは先人の知恵。
上図のようにソートできるようになりました。
IComparerって「プログラミングC#」で、ほけーと読んでたけど、便利ですね。
VBからC#への変換はツールがありそうだけど、手作業で作ってみました。
#region //comparer public class SampleComparer: IComparer { private ListSortDirection _direction; //ソートの向き(昇順/降順) private PropertyDescriptor _property; //ソート項目 public SampleComparer(PropertyDescriptor prop, ListSortDirection direction) { this._property = prop; this._direction = direction; } //同値の場合ゼロを返します。 int IComparer .Compare(T objX, T objY) { //比較対象のオブジェクトからクリックしたプロパティを取得します。 object valX = this.GetPropValue(objX, this._property.Name); object valY = this.GetPropValue(objY, this._property.Name); //directionの値(昇順/降順)に応じて取得した値を比較します。 if (this._direction == ListSortDirection.Ascending) return this.CompareAsc(valX, valY); else return this.CompareDesc(valX, valY); } //昇順で比較を行います。 private int CompareAsc(object valX, object valY) { return valX.ToString().CompareTo(valY.ToString()); } //降順で比較を行います。 private int CompareDesc(object valX, object valY) { return (this.CompareAsc(valX, valY) * -1); } //プロパティ値を取得します。 private object GetPropValue(T val, string prop) { PropertyInfo propInfo = val.GetType().GetProperty(prop); return propInfo.GetValue(val, null); } } #endregion #region //BindingList public class SortBindingList : BindingList { private bool _isSorted; //ソート済みか否かを識別します。 //ソート項目を保持します。 private PropertyDescriptor _sortProperty; //ソート方向(昇順/降順)を保持します。 private ListSortDirection _sortDirection; //リストをバインドします。 public SortBindingList(T[] items) { *1; } } #endregion
あとは、List
this.view.DataSource = new SortBindingList(data.ToArray());
*1:List
今更ながら、C#でクリップボードの実装をしました。
PDICみたいなクリップボード監視できないかなあ?とG先生に聞いてみたところ、下記サイトがありました。OSZありがたい
http://www.k4.dion.ne.jp/~anis7742/codevault/00130.html
早速委譲アダプタで実装です。
でも「Disposal必須」だそうで注意が必要です。
MyClipComboBox.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Forms; namespace ABCS.UserClass { public class MyClipComboBox : ComboBox, IDisposable { //クリップボード監視 private ClipBoardWatcher cbwAdapter; public MyClipComboBox() : base() { this.cbwAdapter = new ClipBoardWatcher(); this.cbwAdapter.DrawClipBoard += (sender, e2) => { if (Clipboard.ContainsText()) { //this.listBox1.Items.Add(Clipboard.GetText()); String clipText = Clipboard.GetText(); if (!this.Items.Contains(clipText)) { this.Items.Add(clipText); } this.SelectedItem = clipText; //this.SelectedText = clipText; } }; } protected override void Dispose(bool disposing) { this.cbwAdapter.Dispose(); base.Dispose(disposing); } } }
Disposal管理にヘルパーを実装。
単純なシングルトンです〜。
MyDisposalHelper.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ABCS.UserClass { public class MyDisposalHelper { private static ListshouldDisposes = new List (); private static MyDisposalHelper singleton = new MyDisposalHelper(); MyDisposalHelper() { } public static MyDisposalHelper GetMyDisposalHelper() { return MyDisposalHelper.singleton; } public static void Add(IDisposable objDisposal ) { MyDisposalHelper.shouldDisposes.Add(objDisposal); } public static void DoDispose() { foreach (IDisposable disposal in MyDisposalHelper.shouldDisposes) { disposal.Dispose(); } } } }
でメインフォームのOnLoadとOnClosingに下記記述を・・・
Form1.cs
private void Form1_Load(object sender, EventArgs e) { //最後にdispose するオブジェクトの登録 MyDisposalHelper.Add(this.cmbClipText); } private void frmMain_FormClosing(object sender, FormClosingEventArgs e) { //クリップボード解放 //this.cmbClipText.Dispose(); MyDisposalHelper.DoDispose(); }
MyDummySQL ver0.04 NULL率設定できるようになりました。
MyDummySQL、ver0.04になり、挿入時に列にNullを入れる確率を0%〜100%に設定できるようになりました。
ダウンロードは以下のURLからどうぞ。↓
http://la-bit.sakura.ne.jp/download/mydummysql/
動作確認はWindows7とWinXPModeで行っています。
実行には.NETFramework4が必要です。↓
http://www.microsoft.com/downloads/ja-jp/details.aspx?FamilyID=9cfb2d51-5ff4-4491-b0e5-b386f32c0992
動作の様子の動画です。↓
MyDummySQL ver0.03 日付型・日時型に対応しました。
MyDummySQLのver0.03です。
今回から日付型と日時型に対応しました。
アルゴリズムはちょっと無骨ですけど。(改良の余地があります)
以下からダウンロードできます。↓
http://la-bit.sakura.ne.jp/download/mydummysql/
あ、実行には.NETFramework4が必要です。↓
http://www.microsoft.com/downloads/ja-jp/details.aspx?FamilyID=9cfb2d51-5ff4-4491-b0e5-b386f32c0992
次は、NULL挿入率を設定できるようにしたいな。
あと、タブオーダーもそろそろそろえないと。
MySQL用ダミーデータ作成ツール MyDummySQL ve0.1 を作ってみた
ちらほらと作っていたMyDummySQL、ver0.1になりました。
すみません。ver0.1にはMySQLのライブラリが入っていませんでした。そのため動作しませんでした。
今はMySQLライブラリを追加したver0.2を下記URLに置いています。
ve0.2は開発PCとは別PC(XPMode)で、動作確認しています。
どうもすみませんでした。m(_’_)m 以後気をつけます。
下記URLからダウンロードできます。
http://la-bit.sakura.ne.jp/download/mydummysql/
XPModeでの実行の様子。(テーブルに10,000行Insert)
そのうちマニュアル作ります。
あ、日付型、日時型には対応していません。そのうち対応します。
ダミーデータ生成ロジックは以下のUMLの様です。
UMLで作ったら、なんだか1つのクラスに1つの責務のみを与えられるようになり、クラスが単純化した。
実装後のデバックでもバグが少ないような。
main.mdbにID列(数値型)とval列(文字列型)のテーブル作ると、MyDummySQLで読み込めます。
人名辞書とか地名辞書とか登録しておくと良いです。
Context.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using MyDummySQL.FactoryNS; using MyDummySQL.NodeNS; namespace MyDummySQL.ContextNS { abstract class Context { protected string param = ""; protected INode node = null; public int no { get; set; } public Context(string param_, int no_) { this.param = param_; this.no = no_; /* ProgramNodefactory fac = new ProgramNodefactory(); this.node = fac.Create(this); */ } public string NextString() { return this.node.NextString(); } } }
SeqNumberContext.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using MyDummySQL.FactoryNS; namespace MyDummySQL.ContextNS { class SeqNumberContext : Context { public long StartInt = 0; public long EndInt = 0; public SeqNumberContext(string param_, int no_) : base(param_,no_) { this.Parse(); ProgramNodefactory fac = new ProgramNodefactory(); this.node = fac.Create(this); } private void Parse() { char sep = { ',' }; string p = this.param.Split(sep); if (p.Length < 2) { throw new ArgumentException("順序番号コマンドの引数は2つ指定して下さい。"); } long.TryParse(p[0], out this.StartInt); long.TryParse(p[1], out this.EndInt); } } }
SeqAccessTableContext.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using MyDummySQL.FactoryNS; namespace MyDummySQL.ContextNS { class SeqAccessTableContext : Context { public string TableName; public SeqAccessTableContext(string param_, int no_) : base(param_,no_) { this.Parse(); ProgramNodefactory fac = new ProgramNodefactory(); this.node = fac.Create(this); } private void Parse() { this.TableName = this.param; } } }
列ダミーデータジェネレーターはINodeで。
INode.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace MyDummySQL.NodeNS { interface INode { //long NextInt(); string NextString(); } }
INodeの実装例
SeqNumberNode.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace MyDummySQL.NodeNS { class SeqNumberNode : INode { private long startInt = 0; private long endInt = 0; private long currentInt = 0; public SeqNumberNode(long startInt_, long endInt_) { //ガード if (startInt_ >= endInt_) { ArgumentException aexcep = new ArgumentException("startIntがendIntより大きな数です。"); throw aexcep; } this.startInt = startInt_; this.endInt = endInt_; this.currentInt = this.startInt - 1; } public string NextString() { //インクリメント this.currentInt++; //フィルター、リミッター if (this.currentInt <= this.startInt) { this.currentInt = this.startInt; } if (this.currentInt > this.endInt) { this.currentInt = this.startInt; } //戻り値 return this.currentInt.ToString(); } } }
INodeの実装例2(Accessテーブル読み込み)
SeqAccessTableNode.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data; using MyDummySQL.DAOs; namespace MyDummySQL.NodeNS { class SeqAccessTableNode : INode { private DataTable table = null; private int no = 0; public SeqAccessTableNode(string tableName) { using (DAOContext con = new DAOContext(AccessConstring.conString)) { con.OpenConnection(); tableDAO dao = new tableDAO(con, tableName); this.table = dao.selectAll(); con.CloseConnection(); } } public string NextString() { string ret = this.table.Rows[this.no]["val"].ToString(); this.no++; if (this.no >= this.table.Rows.Count) { this.no = 0; } return ret; } } }
Contextのファクトリ
ContextFactory.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using MyDummySQL.ContextNS; namespace MyDummySQL.FactoryNS { class ContextFactory { public ContextFactory() { } public Context Create(string atomParam, int no) { char sep = { ':' }; string parts = atomParam.Split(sep); //ガード if (parts.Length != 2) { throw new ArgumentException("アトムコマンドのフォーマットエラーです。「:」で区切ってください。"); } switch (parts[0].ToLower()) { case "seqint": return new SeqNumberContext(parts[1], no); //break; case "rndint": return new RandomNumberContext(parts[1], no); //break; case "seqactbl": return new SeqAccessTableContext(parts[1], no); case "rndactbl": return new RandomAccessTableContext(parts[1], no); case "seqmstbl": return new SeqMySQLTableContext(parts[1], no); case "rndmstbl": return new RandomMySQLTableContext(parts[1], no); case "const": return new ConstStringContext(parts[1], no); default: throw new ArgumentException("存在しないアトムコマンドです。"); } } } }
INodeのファクトリ
ProgramNodeFactory.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using MyDummySQL.ContextNS; using MyDummySQL.NodeNS; namespace MyDummySQL.FactoryNS { class ProgramNodefactory { private Listnodes = new List (); public ProgramNodefactory() { } /* * 基底クラスを引数にしない public void Visit(Context cxt) { } */ public INode Create(Context cxt) { NotImplementedException excep = new NotImplementedException("このメソッドの引数クラスは抽象クラスです。"); throw excep; //return null; } public INode Create(SeqNumberContext seqCtx) { return new SeqNumberNode(seqCtx.StartInt, seqCtx.EndInt); } public INode Create(RandomNumberContext rndCxt) { return new RandomNumberNode(rndCxt.StartInt, rndCxt.EndInt); } public INode Create(SeqAccessTableContext seqAcTblCxt) { return new SeqAccessTableNode(seqAcTblCxt.TableName); } public INode Create(RandomAccessTableContext rndAcTblCxt) { return new RandomAccessTableNode(rndAcTblCxt.TableName); } public INode Create(SeqMySQLTableContext seqMsTblCxt) { return new SeqMySQLTableNode(seqMsTblCxt.TableName, seqMsTblCxt.ColName); } public INode Create(RandomMySQLTableContext rndMsTblCxt) { return new RandomMySQLTableNode(rndMsTblCxt.TableName, rndMsTblCxt.ColName); } public INode Create(ConstStringContext cstStrgCxt) { return new ConstStringNode(cstStrgCxt.ConstString); } } }
列のダミーデータの生成をINodeに委譲し使う側。
ColumnDataGenerator.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using MyDummySQL.ContextNS; using MyDummySQL.FactoryNS; namespace MyDummySQL.GeneratorNS { class ColumnDataGenerator { private Listcontexts = new List (); private string columnName = ""; public ColumnDataGenerator(string columnName_, string param_) { this.columnName = columnName_; this.contexts = this.ParseParam(param_); } private List ParseParam(string param) { char sep = { '|' }; string atoms = param.Split(sep); int no = 0; List cxts = new List (); ContextFactory fac = new ContextFactory(); no = 1; foreach (string atom in atoms) { if (string.IsNullOrEmpty(atom)) { continue; } Context cxt = fac.Create(atom,no); no++; cxts.Add(cxt); } return cxts; } public string BuildColumnData() { string ret = ""; foreach (Context cxt in this.contexts) { ret += cxt.NextString().ToString(); } return ret; } } }
列名と列ダミーデータの対応を取るクラス。
ColumnData.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using MyDummySQL.GeneratorNS; namespace MyDummySQL.Columns { class ColumnData { //[ColumnName, Generator]の組 private DictionaryaryColumnData = new Dictionary (); //[ColumnName, Param]の組 private Dictionary paramsByColumn = new Dictionary (); public ColumnData(Dictionary paramsByColumn_) { this.paramsByColumn = paramsByColumn_; foreach (var key in this.paramsByColumn.Keys) { this.aryColumnData.Add(key, new ColumnDataGenerator(key,this.paramsByColumn[key])); } } //[ColumnName, 生成したColumnValue]の組 public Dictionary GenerateNext() { Dictionary generatedValuesByColumn = new Dictionary (); foreach (var key in this.aryColumnData.Keys) { ColumnDataGenerator g = this.aryColumnData[key]; string columnName = key; string columnValue = g.BuildColumnData(); generatedValuesByColumn.Add(columnName, columnValue); } return generatedValuesByColumn; } } }