WindowsFormアプリの調査

プロジェクト構成

適切な粒度でライブラリ化して開発資産にする(2/2) - @IT

エクセル

表を選択後、コンテキストメニューから並べ替え、ユーザー設定の並べ替えにてタスク一覧を管理。

excel-microsoft.info www.becoolusers.com

クリックワンス

Insider.NET > ClickOnceの真実 - @IT

タイマー処理

garafu.blogspot.jp

テーブルレイアウト

手順 4: TableLayoutPanel コントロールを使用したフォームのレイアウトの設定

SQL Server 2008 ページング

itmemo.net-luck.com kosukety.org

table - pubs / sample
select * from (
    select *, ROW_NUMBER() over(order by phone) rownum from authors 
    ) t
where rownum between 10 and 20
データグリッドビュー
参照用共通カスタムデータグリッドビュー
// ReadonlyDataGridView.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WinFormUc
{
    public partial class ReadonlyDataGridView : DataGridView
    {
        public ReadonlyDataGridView()
        {
            InitializeComponent();

            // 初期設定
            this.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
            this.MultiSelect = false;
            this.AllowUserToAddRows = false;
            this.AllowUserToResizeRows = false;
            this.RowHeadersVisible = false;
            this.ReadOnly = true;
            
        }

        protected override void OnPaint(PaintEventArgs pe)
        {
            base.OnPaint(pe);
        }
    }
}
// DataGridViewHelper.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WinFormUc
{
    /// <summary>
    /// DataGridViewHelperクラス
    /// </summary>
    public static class DataGridViewHelper
    {
        #region カラム追加
        /// <summary>
        /// カラム追加
        /// </summary>
        /// <param name="dgv">対象グリッドビュー</param>
        /// <param name="propertyName">プロパティ名</param>
        /// <param name="headerText">ヘッダーテキスト</param>
        /// <param name="visible">列の表示/非表示</param>
        /// <param name="witdh">列幅</param>
        public static void AddColumn(DataGridView dgv, string propertyName, string headerText, bool visible, int witdh)
        {
            // DataGridViewColumnオブジェクトを生成
            DataGridViewTextBoxColumn column = new DataGridViewTextBoxColumn();
            // セルに表示するデータソースの指定(DataRowの列名や、独自クラスのプロパティ名を指定)
            column.DataPropertyName = propertyName;
            // ヘッダーのテキスト
            column.HeaderText = headerText;
            // 列の表示/非表示
            column.Visible = visible;
            // 列幅
            column.Width = witdh;
            // ユーザーによる列幅の変更可否
            column.Resizable = DataGridViewTriState.True;
            // 追加
            dgv.Columns.Add(column);
        }
        #endregion

    }
}
// SampleForm.cs
private void btnSetGrid_Click(object sender, EventArgs e)
{
    DataGridViewHelper.AddColumn(this.commonDataGridView1, "col_0", "データ0", true, 100);
    DataGridViewHelper.AddColumn(this.commonDataGridView1, "col_1", "データ1", true, 100);
    DataGridViewHelper.AddColumn(this.commonDataGridView1, "col_2", "データ2", true, 100);

    // データグリッドビューの設定
    this.commonDataGridView1.AutoGenerateColumns = false;
    this.commonDataGridView1.DataSource = this.MakeDataTable();

    // ソート設定
    foreach (DataGridViewColumn c in this.commonDataGridView1.Columns)
    {
        c.SortMode = DataGridViewColumnSortMode.Programmatic;
    }

    this.commonDataGridView1.ColumnHeaderMouseClick += CommonDataGridView1_ColumnHeaderMouseClick;
}

private void CommonDataGridView1_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
    // ヘッダのDataPropertyNameによりsortするsqlを実行
    DataGridView dgv = sender as DataGridView;
    MessageBox.Show("header click:" + this.commonDataGridView1.Columns[e.ColumnIndex].DataPropertyName);
}

private DataTable MakeDataTable()
{
    string[] id = { "S0001", "S0002", "S0003", "S0004", "S0005", "S0006" };
    string[] name = { "あんぱん", "メロンパン", "カレーパン", "いちごじゃむパン", "チョココロネ", "クロワッサン" };
    string[] value = { "100", "105", "110", "115", "120", "125" };

    DataTable dt = new DataTable();
    dt.Columns.Add("col_0");
    dt.Columns.Add("col_1");
    dt.Columns.Add("col_2");

    // DataTableにデータを格納します。
    for (int i = 0; i < 5; i++)
    {
        dt.Rows.Add(dt.NewRow());
        dt.Rows[i]["col_0"] = id[i];
        dt.Rows[i]["col_1"] = name[i];
        dt.Rows[i]["col_2"] = value[i];
    }

    return dt;
}
ユーザーコントロールを作成する

http://blog.hiros-dot.net/?cat=153

code.msdn.microsoft.com

codezine.jp

TextBoxに数字しか入力できないようにする: .NET Tips: C#, VB.NET

KeyPressでCtrlを押している状態を知りたい

数値入力テキストボックス
using System;
using System.ComponentModel;
using System.Windows.Forms;
using System.Security.Permissions;

namespace WinFormUc
{
    /// <summary>
    /// 数値入力テキストボックス
    /// </summary>
    public partial class TextBoxNumeric : TextBox
    {

        #region 変数・プロパティ

        /// <summary>
        /// メッセージ:WM_PASTE 
        /// </summary>
        private const int WM_PASTE = 0x302;

        /// <summary>
        /// 数字以外で入力が可能な文字
        /// </summary>
        private char[] allowKeyChars;

        /// <summary>
        /// IMEモード
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new ImeMode ImeMode
        {
            get { return base.ImeMode; }
            set { }
        }

        /// <summary>
        /// MaxLength
        /// </summary>
        [Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public new int MaxLength
        {
            get { return base.MaxLength; }
            set { base.MaxLength = value; }
        }

        #endregion

        #region コンストラクタ
        /// <summary>
        /// コンストラクタ
        /// </summary>
        public TextBoxNumeric()
            : base()
        {
            //IMEを無効にする
            base.ImeMode = ImeMode.Disable;
            //数字以外で入力が可能な文字
            this.SetAllowKeyChars(new char[] { '\b' });
        }
        #endregion

        #region WndProc
        /// <summary>
        /// WndProc
        /// </summary>
        [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        protected override void WndProc(ref Message m)
        {
            if (m.Msg == WM_PASTE)
            {
                IDataObject iData = Clipboard.GetDataObject();
                //文字列がクリップボードにあるか
                if (iData != null && iData.GetDataPresent(DataFormats.Text))
                {
                    string clipStr = (string)iData.GetData(DataFormats.Text);
                    //クリップボードの文字列が数字のみか調べる
                    if (!System.Text.RegularExpressions.Regex.IsMatch(
                        clipStr,
                        @"^[0-9]+$"))
                    {
                        return;
                    }
                }
            }

            base.WndProc(ref m);
        }
        #endregion

        #region 数字以外で入力が可能な文字を設定する
        /// <summary>
        /// 数字以外で入力が可能な文字を設定する
        /// </summary>
        public void SetAllowKeyChars(char[] keyChars)
        {
            this.allowKeyChars = keyChars;
        }
        #endregion


        #region 数字以外で入力が可能な文字を取得する
        /// <summary>
        /// 数字以外で入力が可能な文字を取得する
        /// </summary>
        public char[] GetAllowKeyChars()
        {
            return this.allowKeyChars;
        }
        #endregion

        #region OnKeyPress
        /// <summary>
        /// OnKeyPress
        /// </summary>
        protected override void OnKeyPress(KeyPressEventArgs e)
        {
            base.OnKeyPress(e);

            if (((System.Windows.Forms.Control.ModifierKeys & Keys.Control) == Keys.Control)
                && e.KeyChar == (char)22)
            {
                // ctrl + v
            }
            else
            if (((System.Windows.Forms.Control.ModifierKeys & Keys.Control) == Keys.Control)
                && e.KeyChar == (char)3)
            {
                // ctrl + c
            }
            else
            //数字以外が入力された時はキャンセルする
            if ((e.KeyChar < '0' || '9' < e.KeyChar) &&
                Array.IndexOf(this.allowKeyChars, e.KeyChar) < 0)
            {
                e.Handled = true;
            }
        }
        #endregion
    }
}
日付用テキストボックス
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Text.RegularExpressions;
using System.Security.Permissions;

namespace WinFormUc
{
    /// <summary>
    /// 日付用テキストボックス
    /// </summary>
    public partial class TextBoxDate : TextBox
    {
        #region 変数・プロパティ

        /// <summary>
        /// メッセージ:WM_PASTE 
        /// </summary>
        protected const int WM_PASTE = 0x302;

        /// <summary>
        /// 数字以外で入力が可能な文字
        /// </summary>
        private char[] allowKeyChars;

        /// <summary>
        /// IMEモード
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new ImeMode ImeMode
        {
            get { return base.ImeMode; }
            set { }
        }

        /// <summary>
        /// MaxLength
        /// </summary>
        [Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public new int MaxLength
        {
            get { return base.MaxLength; }
            set { base.MaxLength = value; }
        }

        #endregion

        #region コンストラクタ
        /// <summary>
        /// コンストラクタ
        /// </summary>
        public TextBoxDate()
            : base()
        {
            //数字以外で入力が可能な文字
            this.SetAllowKeyChars(new char[] { '\b', '/' });
        }
        #endregion

        #region WndProc
        /// <summary>
        /// WndProc
        /// </summary>
        [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        protected override void WndProc(ref Message m)
        {
            if (m.Msg == WM_PASTE)
            {
                IDataObject iData = Clipboard.GetDataObject();
                //文字列がクリップボードにあるか
                if (iData != null && iData.GetDataPresent(DataFormats.Text))
                {
                    string clipStr = (string)iData.GetData(DataFormats.Text);
                    //クリップボードの文字列が数字 or '/'か調べる
                    if (!System.Text.RegularExpressions.Regex.IsMatch(
                        clipStr,
                        @"^([0-9]|/)+$"))
                    {
                        return;
                    }
                }
            }

            base.WndProc(ref m);
        }
        #endregion

        #region OnLeave
        /// <summary>
        /// OnLeave
        /// </summary>
        protected override void OnLeave(EventArgs e)
        {
            base.OnLeave(e);
            this.Text = this.ConvertDateFormat(this.Text);
        }
        #endregion

        #region OnKeyPress
        /// <summary>
        /// OnKeyPress
        /// </summary>
        protected override void OnKeyPress(KeyPressEventArgs e)
        {
            base.OnKeyPress(e);

            if (((System.Windows.Forms.Control.ModifierKeys & Keys.Control) == Keys.Control)
                && e.KeyChar == (char)22)
            {
                // ctrl + v
            }
            else
            if (((System.Windows.Forms.Control.ModifierKeys & Keys.Control) == Keys.Control)
                && e.KeyChar == (char)3)
            {
                // ctrl + c
            }
            else
            //数字以外が入力された時はキャンセルする
            if ((e.KeyChar < '0' || '9' < e.KeyChar) &&
                Array.IndexOf(this.allowKeyChars, e.KeyChar) < 0)
            {
                e.Handled = true;
            }
        }
        #endregion

        #region 数字以外で入力が可能な文字を設定する
        /// <summary>
        /// 数字以外で入力が可能な文字を設定する
        /// </summary>
        public void SetAllowKeyChars(char[] keyChars)
        {
            this.allowKeyChars = keyChars;
        }
        #endregion


        #region 数字以外で入力が可能な文字を取得する
        /// <summary>
        /// 数字以外で入力が可能な文字を取得する
        /// </summary>
        public char[] GetAllowKeyChars()
        {
            return this.allowKeyChars;
        }
        #endregion

        #region 入力された日付文字列を変換
        /// <summary>
        /// 入力された日付文字列を変換
        /// </summary>
        /// <param name="inDate">入力日付文字列</param>
        /// <returns>変換した日付文字列</returns>
        private string ConvertDateFormat(string inDate)
        {
            string resultStr = inDate;
            this.BackColor = Color.White;

            if (Regex.IsMatch(inDate, @"^[0-9]{6}99$"))
            {
                // yyyyMMdd:format:で末尾2桁が99の場合
                string year = inDate.Substring(0, 4);
                string month = inDate.Substring(4, 2);
                string dateStr = string.Format("{0}/{1}/{2}", year, month, 1);

                DateTime checktDate;
                if (DateTime.TryParse(dateStr, out checktDate))
                {
                    DateTime d = checktDate.AddMonths(1).AddDays(-1);
                    resultStr = d.ToString("yyyy/MM/dd");
                }
                else
                {
                    this.BackColor = Color.Pink;
                }
            }
            else if (Regex.IsMatch(inDate, @"^[0-9]{8}$"))
            {
                // yyyyMMdd:format:で末尾2桁が99以外の場合
                string year = inDate.Substring(0, 4);
                string month = inDate.Substring(4, 2);
                string day = inDate.Substring(6, 2);
                string dateStr = string.Format("{0}/{1}/{2}", year, month, day);

                DateTime checkDate;
                if (DateTime.TryParse(dateStr, out checkDate))
                {
                    resultStr = dateStr;
                }
                else
                {
                    this.BackColor = Color.Pink;
                }
            }
            else if (Regex.IsMatch(inDate, @"^[0-9]{4}/[0-9]{1,2}/[0-9]{1,2}$"))
            {
                // yyyy/MM/dd:formatの場合
                if (Regex.IsMatch(inDate, @"^[0-9]{4}/[0-9]{1,2}/99$"))
                {
                    // yyyy/MM/dd:format:で末尾2桁が99の場合
                    string[] dateDatas = inDate.Split('/');
                    string year = dateDatas[0];
                    string month = dateDatas[1];
                    string dateStr = string.Format("{0}/{1}/{2}", year, month, 1);

                    DateTime checkDate;
                    if (DateTime.TryParse(dateStr, out checkDate))
                    {
                        resultStr = checkDate.AddMonths(1).AddDays(-1).ToString("yyyy/MM/dd");
                    }
                    else
                    {
                        this.BackColor = Color.Pink;
                    }
                }
                else
                {
                    // yyyy/MM/dd:format:で末尾2桁が99以外の場合
                    DateTime result;
                    if (DateTime.TryParse(inDate, out result))
                    {
                        resultStr = inDate;
                    }
                    else
                    {
                        this.BackColor = Color.Pink;
                    }
                }
            }
            else
            {
                this.BackColor = Color.Pink;
            }

            return resultStr;
        }
        #endregion

    }
}
コンボボックスの注意点

[Winforms] ComboBoxでDataSource=nullをすると、ドロップダウンに空行が残ってしまう

ComboBox(Forms) の DataSource&nbsp;を使用するときの注意点netplanetes.wordpress.com

グローバル変数

stackoverflow.com

フォームをTOPへ表示

nanoappli.com

log4net

Apache log4net – Download Apache log4net - Apache log4net

kazenetu.exblog.jp

// sample.cs - Logger
Logger.Info("test");
// Assemblyinfo.cs - log4net設定
[assembly: log4net.Config.XmlConfigurator(Watch = true)]
// Logger.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using log4net;

namespace xxxx.Utility.Log
{
    /// <summary>
    /// Logヘルパークラス
    /// </summary>
    public static class Logger
    {
        #region 変数・プロパティ

        /// <summary>
        /// Logger
        /// </summary>
        public static ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        #endregion

        #region
        /// <summary>
        /// Fatal:システム停止するような致命的な障害
        /// </summary>
        /// <param name="msg"></param>
        public static void Fatal(string msg)
        {
            logger.Fatal(msg);
        }
        #endregion

        #region
        /// <summary>
        /// Error:システム停止はしないが、問題となる障害
        /// </summary>
        /// <param name="msg"></param>
        public static void Error(string msg)
        {
            logger.Error(msg);
        }
        #endregion

        #region
        /// <summary>
        /// Warn:障害ではない注意警告
        /// </summary>
        /// <param name="msg"></param>
        public static void Warn(string msg)
        {
            logger.Warn(msg);
        }
        #endregion

        #region
        /// <summary>
        /// Info:操作ログなどの情報
        /// </summary>
        /// <param name="msg"></param>
        public static void Info(string msg)
        {
            logger.Info(msg);
        }
        #endregion

        #region
        /// <summary>
        /// Debug:開発用のデバッグメッセージ
        /// </summary>
        /// <param name="msg"></param>
        public static void Debug(string msg)
        {
            logger.Debug(msg);
        }
        #endregion
    }
}
<!-- app.config -->
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <!--これを最初に持ってくること-->
  <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />
  </configSections>
  
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
  </startup>

  <!-- log4net -->
  <log4net>
    <!-- file -->
    <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
      <!-- ログ・ファイル名の先頭部分 -->
      <param name="File" value=".\log\Trace_" />
      <!-- ファイル名の日付部分 -->
      <param name="DatePattern" value='yyyyMMdd".log"' />
      <!-- 日付ごとにファイルを作成することを指定 -->
      <param name="RollingStyle" value="date" />
      <!-- ログ・ファイル名が固定ではないので“false”を指定 -->
      <param name="StaticLogFileName" value="false" />
      <!-- 追加書き込み -->
      <param name="AppendToFile" value="true" />
      <!-- 全てのログ・レベルとする -->
      <filter type="log4net.Filter.LevelRangeFilter">
        <param name="LevelMax" value="FATAL" />
        <param name="LevelMin" value="DEBUG" />
      </filter>
      <!-- rollingStyle がSizeまたはCompositeの時の最大ファイルサイズ -->
      <param name="MaximumFileSize" value="10MB" />
      <!-- ファイルを切替えるマックス数。ここでは3世代まで管理する -->
      <param name="MaxSizeRollBackups" value="3" />

      <!-- ログの出力書式(%C、%F、%l、%L、%Mの場合は処理負荷が高く)-->
      <layout type="log4net.Layout.PatternLayout">
        <!--<ConversionPattern value="%d,[%-5p],%F(%L),%C,%M,%m%n" />-->
        <!--<ConversionPattern value="%d,[%-5p],%C,%M,%m%n" />-->
        <ConversionPattern value="%d,[%-5p],%m%n" />
      </layout> 
    </appender>

    <!-- console -->
    <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
      <layout type="log4net.Layout.PatternLayout">
        <!--<ConversionPattern value="%d,[%-5p],%F(%L),%C,%M,%m%n" />-->
        <!--<ConversionPattern value="%d,[%-5p],%C,%M,%m%n" />-->
        <ConversionPattern value="%d,[%-5p],%m%n" />
      </layout>
    </appender>

    <!-- trace -->
    <appender name="TraceAppender" type="log4net.Appender.TraceAppender">
      <layout type="log4net.Layout.PatternLayout">
        <!--<ConversionPattern value="%d,[%-5p],%F(%L),%C,%M,%m%n" />-->
        <!--<ConversionPattern value="%d,[%-5p],%C,%M,%m%n" />-->
        <ConversionPattern value="%d,[%-5p],%m%n" />
      </layout>
    </appender>
    <root>
      <!-- 警告以上のログを出力したい場合 -->
      <level value="All" />
      <!-- どのログ出力先を使用するか -->
      <appender-ref ref="RollingFileAppender" />
      <appender-ref ref="ConsoleAppender" />
      <appender-ref ref="TraceAppender" />
    </root>
  </log4net>
  
</configuration>