[]
        
(Showing Draft Content)

テンプレートデザイナの制限事項

このトピックでは、.NETプロジェクトのテンプレートデザイナにおける制限事項について説明します。.NETプロジェクトのテンプレートデザイナは、内部的に.NET Frameworkランタイム上で動作しています。そのため、.NET プロジェクトで作成されたクラスをそのまま扱うことができず、以下の機能には一部制限があります。

  • セルに画像を設定する方法

  • MultiRow標準セルのカスタマイズ機能

  • MultiRow標準セルを継承したユーザー定義セル

これらの制限事項を回避する方法については、「.NET Frameworkプロジェクトによるデザイン方法」をご参照ください。

セルに画像を設定する方法

ImageCellなどの画像を設定する方法について、.NET Frameworkではリソースの選択画面を表示し、インポートボタンから画像を読み込むことができますが、.NETプロジェクトでは「インポート」ボタンを使用することはできません。

事前にVisual Studioのリソースエディターから画像を追加し、ImageCellに画像を設定してください。

  1. ソリューションエクスプローラーでプロジェクトを右クリックし、「プロパティ」を開きます。

  2. 「リソース」を開き、画像ファイルを追加します。

    image

  3. テンプレートファイルをデザイナで開き、ImageCellを配置します。

  4. プロパティウィンドウの「Style」から「Image」をクリック、またはImageCellのスマートタグから「画像の選択」をクリックして、追加した画像を選択します。

    image

MultiRow標準セルのカスタマイズ機能

MultiRow標準セルの中には、ユーザーが作成したクラス(カスタムフォーム、カスタムコマンドなど)を設定して機能を拡張できるものがあります。ただし、.NETプロジェクトのテンプレートデザイナではこれらのユーザー定義クラスを読み込めないため、「実行時」タブでは標準の固定動作に置き換えて表示されます。

PopupCell・StickyCell

PopupCellおよびStickyCellでは、ポップアップ表示するフォームを選択できますが、テンプレートデザイナの「実行時」タブでは固定のフォームが表示されます。

image

ButtonCell

ButtonCellでは、ユーザー定義のボタンコマンドを設定できますが、テンプレートデザイナの「実行時」タブではボタンセルをクリックすると固定のメッセージが表示されます。

image

SummaryCell

SummaryCellでは、ユーザー定義の集計クラスを選択できますが、テンプレートデザイナの「実行時」タブでは集計結果がプレビューに反映されません。

image

ShapeCell

ShapeCellでは、ユーザー定義のシェイプレンダラーを選択できますが、テンプレートデザイナの「実行時」タブでは長方形で表示され、ユーザー定義クラス名のウォーターマークが表示されます。また、ユーザー定義のプロパティはプロパティリストには表示されません。

image

CellValidator・CellValidateAction

CellValidatorおよびCellValidateActionにユーザー定義クラスを設定できますが、テンプレートデザイナではユーザー定義のCellValidatorは常に検証成功として扱われ、ユーザー定義のCellValidateActionは実行されません。また、ユーザー定義のプロパティはプロパティリストには表示されません。

// ユーザー定義のCellValidatorクラス
public class CustomCellValidator : CellValidator
{
    protected override bool Validate(ValidateContext context)
    {
        return true;
    }
}

// ユーザー定義のCellValidateActionクラス
public class CustomCellValidateAction : CellValidateAction
{
    protected override void DoAction(ValidateActionContext context)
    {
        MessageBox.Show("Validate");
    }
}

image

image

HeaderDropDownContextMenu

HeaderDropDownContextMenuにユーザー定義のToolStripItemを追加できますが、ユーザー定義のプロパティはプロパティリストには表示されません。

public class CustomToolStripItem : AutoFilterToolStripItem
{
    // ユーザー定義のプロパティ
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    public int PropertyA { get; set; }
}

image

MultiRow標準セルを継承したユーザー定義セル

標準セルを継承したユーザー定義セルの場合、.NETのテンプレートデザイナはユーザー定義セルと同じ名前の代替クラスを内部的に生成し、これをデザイナ上の表示に使用します。代替クラスは継承元である標準セルのメンバーのみを引き継ぐため、ユーザー定義セルに追加されたプロパティ・メソッド・属性や、パラメーター付きコンストラクターは正しく反映されない場合があります。

以下ではそれぞれのケースについて説明します。

ケース別対応表

No

カスタマイズ内容

結果

1

MultiRow 標準セルのプロパティ/メソッドをそのまま使用

制限なし

2

MultiRow 標準セルのプロパティ/メソッドをオーバーライド

制限あり

3

新規プロパティを追加(.NET標準の型:string、int、Colorなど)

制限あり

4

新規プロパティを追加(ユーザー定義型)

条件によって異なります。

  • 制限あり

  • テンプレートデザイナを使用できない

5

新規メソッドを追加

制限なし

6

クラスやプロパティに属性(Attribute)を付与

制限あり

7

パラメーター付きコンストラクター追加

条件によって異なります。

  • 制限あり

  • テンプレートデザイナを使用できない

1. MultiRow標準セルのプロパティ/メソッドをそのまま使用する

MultiRow標準セルが提供するプロパティやメソッドをそのまま使用する場合、テンプレートデザイナで動作します。

2. MultiRow標準セルのプロパティ/メソッドをオーバーライドする

オーバーライドの内容はテンプレートデザイナ上には反映されず、標準セルの描画・挙動のまま表示されます。


例:TextBoxCellを継承し、編集時に独自の背景色・前景色を適用するカスタム編集コントロールを実装

.NET Framework

.NET

B_FW.png

B_NET.png

サンプルコード

// EditType をオーバーライドして独自の編集コントロールを使用するカスタムセル
[ToolboxItem(true)]
[DefaultProperty(nameof(AccentBackColor))]
[Description("EditType プロパティをオーバーライドし、編集モードで独自の編集コントロールを使用するカスタム TextBoxCell の例。")]
public class AccentEditTextBoxCell : TextBoxCell
{
    private Color _accentBackColor = Color.LightGoldenrodYellow;
    private Color _accentForeColor = Color.DarkSlateBlue;

    public AccentEditTextBoxCell()
    {
        Value = "Edit Me";
    }

    [Category("Custom")]
    [Description("カスタム編集コントロールに適用する背景色。")]
    [DefaultValue(typeof(Color), "LightGoldenrodYellow")]
    public Color AccentBackColor
    {
        get { return _accentBackColor; }
        set { _accentBackColor = value.IsEmpty ? Color.LightGoldenrodYellow : value; }
    }

    [Category("Custom")]
    [Description("カスタム編集コントロールに適用する前景色。")]
    [DefaultValue(typeof(Color), "DarkSlateBlue")]
    public Color AccentForeColor
    {
        get { return _accentForeColor; }
        set { _accentForeColor = value.IsEmpty ? Color.DarkSlateBlue : value; }
    }

    // EditType をオーバーライド
    public override Type EditType
    {
        get { return typeof(AccentTextBoxEditingControl); }
    }

    // InitializeEditingControl をオーバーライドして色・スタイルを適用
    protected override void InitializeEditingControl(int rowIndex, object formattedValue, CellStyle style)
    {
        base.InitializeEditingControl(rowIndex, formattedValue, style);

        if (GcMultiRow?.EditingControl is AccentTextBoxEditingControl editingControl)
        {
            editingControl.BackColor = _accentBackColor;
            editingControl.ForeColor = _accentForeColor;
            editingControl.BorderStyle = BorderStyle.FixedSingle;
        }
    }

    public override object Clone()
    {
        AccentEditTextBoxCell cell = base.Clone() as AccentEditTextBoxCell;
        cell._accentBackColor = _accentBackColor;
        cell._accentForeColor = _accentForeColor;
        return cell;
    }
}

public class AccentTextBoxEditingControl : TextBoxEditingControl
{
    public AccentTextBoxEditingControl()
    {
        BorderStyle = BorderStyle.FixedSingle;
    }

    public override void PrepareEditingControlForEdit(bool selectAll)
    {
        base.PrepareEditingControlForEdit(selectAll);
        SelectAll();
    }
}

3. 新規プロパティを追加する(.NET標準の型)

.NET標準の型(string、int、Colorなど)で新規プロパティを追加した場合、値はテンプレートデザイナのプロパティウィンドウから編集できますが、デザイン時プレビューには反映されません。


例:TextBoxCellを継承し、バッジテキストやバッジ色などのカスタム描画用プロパティを追加

.NET Framework

.NET

C_FW.png

C_NET.png

サンプルコード

// .NET 標準の型で新規プロパティを追加し、PaintCellForeground をオーバーライドするサンプル
[ToolboxItem(true)]
[DefaultProperty(nameof(BadgeText))]
[Description("PaintCellForeground をオーバーライドして、標準の描画の上にアクセントラインとバッジを描画するカスタム TextBoxCell の例。")]
public class BadgeTextBoxCell : TextBoxCell
{
    private string _badgeText = "NEW";
    private Color _badgeBackColor = Color.IndianRed;
    private Color _badgeForeColor = Color.White;
    private Color _accentLineColor = Color.IndianRed;
    private bool _showBadge = true;
    private bool _showAccentLine = true;

    public BadgeTextBoxCell()
    {
    }

    public BadgeTextBoxCell(string badgeText)
    {
        BadgeText = badgeText;
    }

    // .NET 標準型(string)の新規プロパティ(プレビューには反映されないが値の編集は可能)
    [Category("Custom Paint")]
    [Description("セルの右上隅に描画する短いラベルテキスト。")]
    [DefaultValue("NEW")]
    [Localizable(true)]
    public string BadgeText
    {
        get { return _badgeText; }
        set { _badgeText = string.IsNullOrEmpty(value) ? "NEW" : value; }
    }

    // .NET 標準型(Color)の新規プロパティ
    [Category("Custom Paint")]
    [Description("バッジの背景色。")]
    [DefaultValue(typeof(Color), "IndianRed")]
    public Color BadgeBackColor
    {
        get { return _badgeBackColor; }
        set { _badgeBackColor = value.IsEmpty ? Color.IndianRed : value; }
    }

    [Category("Custom Paint")]
    [Description("バッジのテキスト色。")]
    [DefaultValue(typeof(Color), "White")]
    public Color BadgeForeColor
    {
        get { return _badgeForeColor; }
        set { _badgeForeColor = value.IsEmpty ? Color.White : value; }
    }

    [Category("Custom Paint")]
    [Description("セル上部に描画するカスタムアクセントラインの色。")]
    [DefaultValue(typeof(Color), "IndianRed")]
    public Color AccentLineColor
    {
        get { return _accentLineColor; }
        set { _accentLineColor = value.IsEmpty ? Color.IndianRed : value; }
    }

    // .NET 標準型(bool)の新規プロパティ
    [Category("Custom Paint")]
    [Description("標準の前景描画後にバッジを描画するかどうか。")]
    [DefaultValue(true)]
    public bool ShowBadge
    {
        get { return _showBadge; }
        set { _showBadge = value; }
    }

    [Category("Custom Paint")]
    [Description("標準の前景描画後にアクセントラインを描画するかどうか。")]
    [DefaultValue(true)]
    public bool ShowAccentLine
    {
        get { return _showAccentLine; }
        set { _showAccentLine = value; }
    }

    // PaintCellForeground をオーバーライドしてカスタム描画を追加
    protected override void PaintCellForeground(CellPaintingEventArgs e)
    {
        base.PaintCellForeground(e);

        Rectangle bounds = e.CellBounds;
        if (bounds.Width < 24 || bounds.Height < 12)
        {
            return;
        }

        Graphics graphics = e.Graphics;
        SmoothingMode oldSmoothingMode = graphics.SmoothingMode;
        graphics.SmoothingMode = SmoothingMode.AntiAlias;

        try
        {
            if (_showAccentLine)
            {
                using (Pen accentPen = new Pen(_accentLineColor, 2f))
                {
                    graphics.DrawLine(accentPen, bounds.Left + 1, bounds.Top + 1, bounds.Right - 2, bounds.Top + 1);
                }
            }

            if (_showBadge && !string.IsNullOrEmpty(_badgeText))
            {
                Size textSize = TextRenderer.MeasureText(_badgeText, e.CellStyle.Font);
                int badgeWidth = textSize.Width + 10;
                int badgeHeight = textSize.Height;

                Rectangle badgeBounds = new Rectangle(
                    bounds.Right - badgeWidth - 4,
                    bounds.Top + 4,
                    badgeWidth,
                    badgeHeight);

                using (GraphicsPath path = CreateRoundedRectangle(badgeBounds, 4))
                using (SolidBrush backBrush = new SolidBrush(_badgeBackColor))
                using (SolidBrush textBrush = new SolidBrush(_badgeForeColor))
                using (StringFormat format = new StringFormat())
                {
                    format.Alignment = StringAlignment.Center;
                    format.LineAlignment = StringAlignment.Center;

                    graphics.FillPath(backBrush, path);
                    graphics.DrawString(_badgeText, e.CellStyle.Font, textBrush, badgeBounds, format);
                }
            }
        }
        finally
        {
            graphics.SmoothingMode = oldSmoothingMode;
        }
    }

    public override object Clone()
    {
        BadgeTextBoxCell cell = base.Clone() as BadgeTextBoxCell;
        cell._badgeText = _badgeText;
        cell._badgeBackColor = _badgeBackColor;
        cell._badgeForeColor = _badgeForeColor;
        cell._accentLineColor = _accentLineColor;
        cell._showBadge = _showBadge;
        cell._showAccentLine = _showAccentLine;
        return cell;
    }

    private static GraphicsPath CreateRoundedRectangle(Rectangle bounds, int radius)
    {
        int diameter = radius * 2;
        Rectangle arc = new Rectangle(bounds.Location, new Size(diameter, diameter));
        GraphicsPath path = new GraphicsPath();

        path.AddArc(arc, 180, 90);
        arc.X = bounds.Right - diameter;
        path.AddArc(arc, 270, 90);
        arc.Y = bounds.Bottom - diameter;
        path.AddArc(arc, 0, 90);
        arc.X = bounds.Left;
        path.AddArc(arc, 90, 90);
        path.CloseFigure();

        return path;
    }
}

4. 新規プロパティを追加する(ユーザー定義型)

ユーザーが定義したプロパティを追加したとき、テンプレートの作成方法によってテンプレートデザイナでの挙動が異なります。


.NETプロジェクトで新規作成したテンプレートの場合

テンプレートデザイナを開くことはできますが、ユーザー定義型のプロパティは代替クラス上でobject型として扱われるため、デザイン時に値を編集できません。また、追加したプロパティに付与した属性は無視され(ケース6参照)、コンストラクター内の初期化ロジックも実行されません(ケース7参照)。


.NET Frameworkプロジェクトから移行したテンプレートの場合

.designer.csに既に設定済みのプロパティ値のコードが含まれているため、コード解析に失敗し、テンプレートデザイナを開くことができません。


例:TextBoxCellを継承し、ユーザー定義の型CheckedListBoxCellOptionsのプロパティを追加

.NET Framework

.NET(新規作成)

.NET(.NET Frameworkから移行)

D_FW.png

D_NET2.png

image

サンプルコード

// ユーザー定義型のプロパティを追加したカスタムセル
[ToolboxItem(true)]
[DefaultProperty(nameof(CheckedListOptions))]
[Description("ユーザー定義型のプロパティを 1 つだけ追加したカスタムセルの例。")]
public class CheckedListBoxCell : TextBoxCell
{
    private CheckedListBoxCellOptions _checkedListOptions;

    public CheckedListBoxCell()
    {
        Value = "CheckedListBoxCell sample";
    }

    // ユーザー定義型(CheckedListBoxCellOptions)のプロパティ(デザイン時は object 型扱いで編集不可)
    [Category("Custom")]
    [Description("別ファイルで定義されたユーザー定義型を持つカスタムプロパティ。")]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    [NotifyParentProperty(true)]
    public CheckedListBoxCellOptions CheckedListOptions
    {
        get
        {
            if (_checkedListOptions == null)
            {
                _checkedListOptions = new CheckedListBoxCellOptions();
            }

            return _checkedListOptions;
        }
    }

    public override object Clone()
    {
        CheckedListBoxCell cell = base.Clone() as CheckedListBoxCell;
        if (_checkedListOptions != null)
        {
            cell._checkedListOptions = _checkedListOptions.Clone();
        }

        return cell;
    }
}
// CheckedListBoxCell で使用するユーザー定義型(代替クラス上では object 型として扱われる)
[TypeConverter(typeof(ExpandableObjectConverter))]
[Description("CheckedListBoxCell が使用するカスタムプロパティ型。")]
public class CheckedListBoxCellOptions
{
    private string _caption = "Selectable Items";
    private Color _highlightColor = Color.SteelBlue;
    private bool _showCheckedCount = true;

    [Category("Appearance")]
    [Description("カスタムプロパティオブジェクトのサンプルキャプション。")]
    [DefaultValue("Selectable Items")]
    [Localizable(true)]
    public string Caption
    {
        get { return _caption; }
        set { _caption = string.IsNullOrEmpty(value) ? "Selectable Items" : value; }
    }

    [Category("Appearance")]
    [Description("カスタムプロパティオブジェクトに格納するサンプルの色の値。")]
    [DefaultValue(typeof(Color), "SteelBlue")]
    public Color HighlightColor
    {
        get { return _highlightColor; }
        set { _highlightColor = value.IsEmpty ? Color.SteelBlue : value; }
    }

    [Category("Behavior")]
    [Description("カスタムプロパティオブジェクトに格納するサンプルのブール値オプション。")]
    [DefaultValue(true)]
    public bool ShowCheckedCount
    {
        get { return _showCheckedCount; }
        set { _showCheckedCount = value; }
    }

    public CheckedListBoxCellOptions Clone()
    {
        return new CheckedListBoxCellOptions
        {
            _caption = _caption,
            _highlightColor = _highlightColor,
            _showCheckedCount = _showCheckedCount
        };
    }

    public override string ToString()
    {
        return "(CheckedListOptions)";
    }
}

5. 新規メソッドを追加する

追加した新規メソッドは、テンプレートデザイナ・実行時ともに動作します。

6. クラスやプロパティに属性(Attribute)を付与する

クラスやプロパティに属性を付与しても、テンプレートデザイナ上では属性は効果を発揮しません。属性に紐づかない他の機能は通常どおり扱えます。

例えば、プロパティにカスタムエディターを指定する属性を付与した場合、.NET Frameworkプロジェクトではプロパティウィンドウから専用ダイアログを呼び出せますが、.NETプロジェクトではカスタムエディターが起動せず、通常の文字列入力になります。

なお、[DesignerSerializer]などコード生成に関わる属性も無視されるため、.designer.csファイルに生成されるコードは .NET Frameworkプロジェクトと異なります。


例:TextBoxCellを継承し、[DesignerSerializer]によるカスタムコード生成と[Editor]によるカスタムダイアログを設定

.NET Framework

.NET

F_FW.png

F_NET.png

サンプルコード

// カスタムエディターとコード生成属性を付与したサンプル
[ToolboxItem(true)]
[Description("業務用のデフォルト値とラベル的なプロンプトプロパティを追加したカスタム TextBoxCell の例。")]
// [DesignerSerializer] コード生成に関わる属性
[DesignerSerializer(typeof(SearchTextBoxCellCodeDomSerializer), typeof(CodeDomSerializer))]
public class SearchTextBoxCell : TextBoxCell
{
    private string _searchPrompt = "Type to filter";

    [Category("Custom")]
    [Description("ToolTipText が未設定の場合に使用するサンプルのプロンプトテキスト。")]
    [DefaultValue("Type to filter")]
    [Localizable(true)]
    // [Editor] でカスタムダイアログを指定
    [Editor(typeof(SearchPromptEditor), typeof(UITypeEditor))]
    public string SearchPrompt
    {
        get { return _searchPrompt; }
        set
        {
            _searchPrompt = string.IsNullOrEmpty(value) ? "Type to filter" : value;
            if (string.IsNullOrEmpty(ToolTipText))
            {
                ToolTipText = _searchPrompt;
            }
        }
    }

    public override object Clone()
    {
        SearchTextBoxCell cell = base.Clone() as SearchTextBoxCell;
        cell._searchPrompt = _searchPrompt;
        return cell;
    }
}

7. パラメーター付きコンストラクターを追加する

パラメーター付きコンストラクターを追加した場合、継承元のセルによってテンプレートデザイナでの扱いが異なります。

以下のセルを継承している場合、テンプレートデザイナを開くことができません。

  • GcDateTimeCell

  • GcTextBoxCell

  • GcComboBoxCell

  • GcMaskCell

  • GcCharMaskCell

  • GcNumberCell

  • GcTimeSpanCell

  • GcAddressBoxCell

  • GcPostalCell

  • GcFontPickerCell

  • GcColorPickerCell

これらのセルでは、.designer.csファイルにパラメーター付きコンストラクターを使ったインスタンス化コードが生成されます。テンプレートデザイナはこの.designer.csファイルを代替クラスで解析しますが、代替クラスは標準セルのメンバーのみを引き継いだクラスであるため、パラメーター付きコンストラクターが存在せず、テンプレートデザイナを開くことができません。

例:GcDateTimeCellを継承し、パラメーター付きコンストラクターを追加

.NET Framework

.NET

G_FW.png

image

サンプルコード

// GcDateTimeCell を継承し、パラメーター付きコンストラクターを追加
[ToolboxItem(true)]
public class GcDateTimeCtorCell : GcDateTimeCell
{
    // パラメーターなしコンストラクターからパラメーター付きへ委譲
    public GcDateTimeCtorCell()
        : this(true)
    {
    }

    // パラメーター付きコンストラクター
    public GcDateTimeCtorCell(bool initialization)
        : base(initialization)
    {

    }
}


上記以外のセルを継承している場合は、テンプレートデザイナは開けますが、コンストラクター内のカスタムロジック(初期化処理、メッセージ表示など)はテンプレートデザイナ上では実行されません。

例:GcCalendarCellを継承し、コンストラクター内でデザイン時にメッセージボックスを表示するロジックを追加

.NET Framework

.NET

テンプレートデザイナを起動する前にメッセージが表示されます

メッセージが表示されません

H_FW.png


サンプルコード

// GcCalendarCell を継承し、コンストラクター内でデザイン時ロジックを実行
[ToolboxItem(true)]
[Description("パラメーターなしコンストラクターで簡単なロジックを実行し、デザイナでのインスタンス化を確認しやすくしたサンプル GcCalendarCell。")]
public class CtorMessageCalendarCell : GcCalendarCell
{
    public CtorMessageCalendarCell()
    {
        Value = DateTime.Today;

        // デザイン時のみメッセージを表示
        if (LicenseManager.UsageMode == LicenseUsageMode.Designtime)
        {
            MessageBox.Show(
                "テンプレートデザイナ起動時にメッセージを表示します",
                "Custom Cell Constructor",
                MessageBoxButtons.OK,
                MessageBoxIcon.Information);
        }
    }
}