UserControls/AbstractSearchControlcs.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ChatworkBulkSender.UserControls
{
    /// <summary>
    /// 検索ボックス部分の基底クラス。
    /// </summary>
    [DesignerCategory("")]
    public abstract class AbstractSearchControl : AbstractUserControl
    {
        protected Panel _panel;
        protected Label _lblSearchBox;
        protected Panel _panelSearchBox;
        protected Button _btnSearch;
        protected CheckBox _chkUnusedData;
        protected Dictionary<string, TextBox> _searchTextBoxes;

        public event EventHandler<Dictionary<string, object>> SearchRequested;

        public AbstractSearchControl()
        {
            //InitializeComponent(); // 基底クラスではInitializeComponentを呼ばない

            _searchTextBoxes = new Dictionary<string, TextBox>();
        }

        protected virtual void InitializeControls()
        {
            // 基本のパネル
            _panel = new Panel();
            _panel.Dock = DockStyle.Fill;

            // 検索条件ラベル
            _lblSearchBox = new Label();
            _lblSearchBox.AutoSize = true;
            _lblSearchBox.Font = new Font("HG丸ゴシックM-PRO", 19.8F, FontStyle.Regular, GraphicsUnit.Point, 128);
            _lblSearchBox.Location = new Point(48, 32);
            _lblSearchBox.Text = " 検索条件 ";

            // 検索条件パネル
            _panelSearchBox = new Panel();
            _panelSearchBox.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
            _panelSearchBox.BorderStyle = BorderStyle.FixedSingle;
            _panelSearchBox.Location = new Point(19, 49);

            // 検索ボタン
            _btnSearch = new Button();
            _btnSearch.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
            _btnSearch.BackColor = Color.Gray;
            _btnSearch.FlatAppearance.BorderSize = 0;
            _btnSearch.Font = new Font("HG丸ゴシックM-PRO", 22.8F);
            _btnSearch.ForeColor = SystemColors.ControlLightLight;
            _btnSearch.Size = new Size(200, 66);
            _btnSearch.Text = "検索";
            _btnSearch.UseVisualStyleBackColor = false;
            _btnSearch.Click += BtnSearch_Click;

            // 未使用データのCheckBox
            _chkUnusedData = new CheckBox();
            _chkUnusedData.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
            _chkUnusedData.Font = new Font("HG丸ゴシック-PRO", 19.8F, FontStyle.Regular, GraphicsUnit.Point, 128);
            _chkUnusedData.Size = new Size(380, 41);
            _chkUnusedData.Text = "未使用フラグ";
            _chkUnusedData.UseVisualStyleBackColor = true;

            var searchFieldsPanel = CreateSearchFIeldsPanel();

            if (_searchTextBoxes != null)
            {
                _panelSearchBox.Controls.Add(searchFieldsPanel);
            }
        }

        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);
            AdjustLayout();
        }

        /// <summary>
        /// 継承先で実装する。
        /// 検索フィールドのパネルを作成。
        /// </summary>
        /// <returns></returns>
        protected abstract Panel CreateSearchFIeldsPanel();

        /// <summary>
        /// レイアウトを調整する。
        /// </summary>
        protected virtual void AdjustLayout()
        {
            if (DesignMode) { return; }

            // 高さの設定は派生クラスに委ねる

            int bottomMargin = 20;
            _btnSearch.Location = new Point(_panelSearchBox.Width - _btnSearch.Width - 20, _panelSearchBox.Height - _btnSearch.Height - bottomMargin);
            _chkUnusedData.Location = new Point(_btnSearch.Left - _chkUnusedData.Width - 10, _btnSearch.Top + (_btnSearch.Height - _chkUnusedData.Height) / 2);
        }

        /// <summary>
        /// 検索条件を取得する。
        /// </summary>
        /// <returns></returns>
        protected virtual Dictionary<string,object> GetSearchCriteria()
        {
            var criteria = new Dictionary<string, object>();

            foreach (var kvp in _searchTextBoxes)
            {
                if (!string.IsNullOrWhiteSpace(kvp.Value.Text))
                {
                    criteria[kvp.Key] = kvp.Value.Text.Trim();
                }
            }

            criteria["IncludeUnused"] = _chkUnusedData.Checked;
            
            return criteria;
        }

        /// <summary>
        /// 検索条件をクリアする。
        /// </summary>
        protected virtual void ClearSeaech()
        {
            foreach (var textBox in _searchTextBoxes.Values)
            {
                textBox.Clear();
            }
            _chkUnusedData.Checked = false;
        }

        /// <summary>
        /// TableLayoutPanelを定義。
        /// </summary>
        /// <param name="tlp"></param>
        /// <param name="labelText"></param>
        /// <param name="fieldName"></param>
        /// <param name="rowIndex"></param>
        /// <param name="columnSpan"></param>
        protected void AddSearchField(TableLayoutPanel tlp, string labelText, string fieldName, int rowIndex, int columnSpan = 1)
        {
            var label = new Label
            {
                Dock = DockStyle.Fill,
                Font = new Font("HG丸ゴシック-PRO", 19.8F, FontStyle.Regular, GraphicsUnit.Point, 128),
                Text = labelText,
                TextAlign = ContentAlignment.MiddleLeft
                ,
            };

            var textBox = new TextBox
            {
                Dock = DockStyle.Fill,
                Font = new Font("HG丸ゴシック-PRO", 19.8F, FontStyle.Regular, GraphicsUnit.Point, 128),
                Margin = new Padding(0)
                ,
            };

            tlp.Controls.Add(label,0,rowIndex);
            tlp.Controls.Add(textBox,1,rowIndex);

            if (columnSpan > 1)
            {
                tlp.SetColumnSpan(textBox,columnSpan);
            }

            _searchTextBoxes[fieldName] = textBox;
        }

        /// <summary>
        /// 検索条件のバリデーション(継承先でオーバーライド)
        /// </summary>
        /// <param name="errorMessage">エラーメッセージ</param>
        /// <returns>バリデーション成功時はtrue</returns>
        protected virtual bool ValidateSearchCriteria(out string errorMessage)
        {
            errorMessage = string.Empty;
            return true;
        }

        protected virtual void BtnSearch_Click(object sender,EventArgs e)
        {
            // バリデーション実行
            string validationError;
            if (!ValidateSearchCriteria(out validationError))
            {
                MessageBox.Show(validationError, "入力エラー", 
                    MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }

            var criteria = GetSearchCriteria();

            SearchRequested?.Invoke(this,criteria);
        }
    }
}