コンテンツへスキップ
ASP.NET AJAX Data Grid: 有効 & 無効 チェックボックスの状態

ASP.NET AJAX Data Grid: 有効 & 無効 チェックボックスの状態

チェックされているかどうか?マルチステートチェックボックスは、今日メニューにあります。もちろん、これは「WebDataGridはすでにチェックボックス列をすぐにサポートしていないのか」という疑問を投げかけます。

10min read

チェックされているかどうか?マルチステートチェックボックスは、今日メニューにあります。もちろん、これは「WebDataGridはすでにチェックボックス列をすぐにサポートしていないのか」という疑問を投げかけます。

はい、トライステートのCheckBoxフィールドをサポートしていますが、もう少し柔軟性が必要な場合があります。Product Ideasフィードバックプラットフォームでお知らせしたように、チェックボックスの状態が増え、バリエーションが有効または無効になることは、ユーザー自身が直接恩恵を受けることができるものです。これは、グリッドの編集動作がチェックボックスフィールドを一括で(列全体と同様に)処理するためであり、列のチェックボックスが編集可能ではないという視覚的な手掛かりがないためでもあります。したがって、各行に設定できる標準のトライステートチェックボックス以上のものが必要な場合は、読み進めてください。私たちが受け取ったフィードバックに基づいて、チームは解決策を準備し、私自身も独自のスピンを追加しました。

セットアップ

ここでは、チェックボックス列がバインドまたはバインドされていないデータグリッドを表示するだけでなく、編集ビヘイビアを使用し、条件または他のデータ列に基づいて各行のチェックボックスを編集可能にするかどうかを制御することも想定しています。このように、3つの状態から、有効と無効を組み合わせて6つに進み、これは複数の列に格納する必要があるかもしれません。データとケースに応じて、追加の列を旗、天気、天気、チェックボックス、または状態全体をアクティブにする必要があります。このようなものの実装は大きく異なる可能性があるため、少し適応が必要な場合がありますが、再利用可能な基本を指摘し、デモコードでオプション機能をマークしてみます。

Basics

無効状態を追加する背後にある考え方は非常に巧妙です - チェックボックスの画像をそれぞれの非アクティブな画像に置き換え、それらの画像に対してランタイムチェックを実行して編集を防ぎます。これにより、視覚的な表示だけでなく、検出に使用できる画像の詳細も制御できます。したがって、3つの画像と、それらのパスと値、およびチェックボックスと非表示の状態セル間のマッピングを含むクライアント側の設定オブジェクトが必要です。

処理するクライアントイベント:

  • 初期化– 追加の状態を持つチェックボックスを確認し、有効/無効の外観を適用します
  • 編集CellValueChangingを処理して、編集が無効にならないようにします。また、API を使用するとイベントが発生するため、クライアント側でプログラムによって値を変更できるようにする場合は、代わりに"_set_value_internal"メソッドを使用する必要があることに注意してください。
  • ヘッダー ボックスでバインドされていないチェック ボックスを使用している場合は、HeaderCheckBoxClickedも処理して、適切な状態とおそらく値を設定する必要があります。

現在のデータからバインドされたフィールドを使用したり、使用できない場合は新しいフィールドを追加したり、フラグを保持するためだけにバインドされていないフィールドを使用したり、クライアントで実行されるロジックに基づいてチェックボックスを有効または無効にしたりすることもできます。

External Flag Approach

これは、標準のチェックボックス機能を使用するとともに、フラグに基づいて編集可能な状態を適用するとともに、別のデータ列、サーバーロジックによって事前に決定され、バインドされていないフィールドとして引き継がれる、または完全にクライアント側のロジックに基づくことができます。実装は本当にあなた次第です、私はデータの一部として別のbool列を使用します - そして私は2つのチェックボックス列を持っているので、最後の2つのフィールドはそれらのために無効なフラグを持っています:

<ig:WebDataGrid ID="WebDataGrid1" runat="server" Height="350px" Width="100%" AutoGenerateColumns="False" DataKeyFields="ID" StyleSetName="IG">
    <Columns>
        <ig:BoundDataField DataFieldName="ID" Key="ID">
            <Header Text="ID" />
        </ig:BoundDataField>
        <ig:BoundDataField DataFieldName="CheckBoxState" Key="CheckBoxState">
            <Header Text="CheckBox State" />
        </ig:BoundDataField>                
        <ig:BoundCheckBoxField DataFieldName="BoundCheckBox" Key="BoundCheckBox" DataType="System.Boolean">
            <Header Text="Bound CheckBox" />
        </ig:BoundCheckBoxField>
        <ig:BoundCheckBoxField Key="DisableBoundCheckBox">
            <Header Text="Check to disable corresponding BoundCheckBox" />
        </ig:BoundCheckBoxField>                
        <ig:UnboundCheckBoxField Key="UnboundCheckBox" HeaderCheckBoxMode="TriState">
            <Header Text="UnboundCheckBox"/>
        </ig:UnboundCheckBoxField>   
        <ig:UnboundCheckBoxField Key="DisableUnboundCheckBox" HeaderCheckBoxMode="TriState">
            <Header Text="Check to disable corresponding UnboundCheckBox" />
        </ig:UnboundCheckBoxField>
        <%-- Hidden columns to store the states for the CheckBoxFields --%>   
        <ig:BoundDataField Key="BoundCheckBoxDisabled" Hidden="true" DataType="System.Boolean">
            <Header Text="Bound CheckBox Disabled?" />
        </ig:BoundDataField>
        <ig:BoundDataField Key="UnboundCheckBoxDisabled" Hidden="true" DataType="System.Boolean">
            <Header Text="Unbound CheckBox Disabled?" />
        </ig:BoundDataField>                      
    </Columns>
    <ClientEvents Initialize="WebDataGrid_Grid_Initialize" HeaderCheckBoxClicked="WebDataGrid_Grid_HeaderCheckboxClicked" />
    <Behaviors>
        <ig:EditingCore>
            <EditingClientEvents CellValueChanging="WebDataGrid_Editing_CellValueChanging" CellValueChanged="WebDataGrid_Editing_CellValueChanged" />
            <Behaviors>
                <ig:CellEditing>
                        <ColumnSettings>
                            <ig:EditingColumnSetting ColumnKey="ID" ReadOnly="True" />
                        </ColumnSettings>
                        <EditModeActions MouseClick="Single" EnableOnKeyPress="true"/>
                </ig:CellEditing>
            </Behaviors>
        </ig:EditingCore>
    </Behaviors>
</ig:WebDataGrid>

これらの値に基づく初期状態が確立され、必要に応じて無効にされたチェックボックスの画像がデフォルトに置き換わります。

var styleName = "<%= this.WebDataGrid1.StyleSetName %>" || "Default";
var clientSettings = {
    "true": { src: "images/" + styleName + "/ig_checkbox_disabled_on.gif", value: true, chkState: 1 },
    "false": {src: "images/" + styleName + "/ig_checkbox_disabled_off.gif", value: false, chkState: 0 },
    "null": { src: "images/" + styleName + "/ig_checkbox_disabled_partial.gif", value: null, chkState: 2 },
    "columns": {2: 6, 4: 7}           
};
 
function WebDataGrid_Grid_Initialize(sender, eventArgs) {
    // Set initial enabled / disabled state for all checkboxes            
    try {
        var rows = sender.get_rows();
        var rowCount = rows.get_length();
        for (var i = 0; i < rowCount; i++) {
            var row = rows.get_row(i);
            for (columnIndex in clientSettings["columns"]){
                // Set the correct enabled/disabled states:
                var checkBoxCell = row.get_cell(columnIndex);
                var hiddenStateCell = row.get_cell(clientSettings["columns"][columnIndex]);
                var isDisabled = hiddenStateCell.get_value();
                SetCheckState(checkBoxCell, isDisabled, hiddenStateCell);
            }
        }
    }
    catch (ex) { }
}
 
function SetCheckState(cell, isDisabled, checkStateCell) {
    // Set Enabled or disabled state to a cell (adjust image and title/alt) and store in secondary cell.
    try {
        if (isDisabled === isCellDisabled(cell)) return;
        var checkBoxElem = cell.get_element().getElementsByTagName("img").item(0); //get checkbox image
        var chkStates = clientSettings[String(cell.get_value())]; //get state info
        if (!chkStates) return;
                
        if (isDisabled === true) {
            // Set the disabled values of src and title for the checkbox
            checkBoxElem.src = chkStates.src;
            checkBoxElem.title = "Disabled " + checkBoxElem.title;
            checkBoxElem.alt = "Disabled " + checkBoxElem.alt;
        }
        else {
            // re-set value to restore state
            checkBoxElem.src = "";
            //use _internal to force setting the same value
            cell._set_value_internal(chkStates.value, chkStates.chkState);
        }
        checkStateCell.set_value(isDisabled); // Store the new checkbox state value in the corresponding hidden checkbox
    }
    catch (ex) { }
}
 
function isCellDisabled(cell) {
    var checkBoxElem = cell.get_element().getElementsByTagName("img").item(0);
    return checkBoxElem && checkBoxElem.src.toLowerCase().indexOf("disabled") >= 0;
}

無効なチェックボックスとバインドされていないフィールドの編集を防止すると、ヘッダーボックスの使用時に状態が保持されます。

function WebDataGrid_Editing_CellValueChanging(sender, eventArgs) {
    // Prevent edit actions on disabled checkboxes
    try {
        var currCell = eventArgs.get_cell();
        if (isCellDisabled(currCell))
            eventArgs.set_cancel(true); // cancel event to prevent value change
    }
    catch (ex) { }
}
 
function WebDataGrid_Grid_HeaderCheckboxClicked(sender, eventArgs) {
    var columnIndex = eventArgs.get_column().get_index();
    var rows = sender.get_rows();
    var rowCount = rows.get_length();
 
    // When the header of the "UnboundCheckBox" column is clicked,
    // set the check states for all while maintaining enabled/disabled states
    if (clientSettings["columns"][columnIndex]) {
        for (var i = 0; i < rowCount; i++) {
            var row = rows.get_row(i);
            var unboundCheckBoxCell = row.get_cell(columnIndex);
            var hiddenUnboundCheckBoxCell = unboundCheckBoxCell.get_row().get_cell(clientSettings["columns"][columnIndex]);
            var unboundCheckBoxCellVal = hiddenUnboundCheckBoxCell.get_value();
            SetCheckState(unboundCheckBoxCell, unboundCheckBoxCellVal, hiddenUnboundCheckBoxCell);
        }
    }
}

もちろん、非連結フィールドの状態を保持することは、ヘッダーボックス自体と同様にオプションであり、何が必要かの問題です。この時点で、SetCheckState関数を使用して状態を切り替え、必要に応じてさまざまな方法でユーザーに提供できます (デモ コード、隣接する標準チェック ボックス フィールドの値の変更の処理を参照)。

チェックボックスの有効/無効は、ユーザーから非表示になる「フラグ」のセカンダリ列(最後の2つ)に基づいています。

PSクライアント設定で列のペアの読みやすさを向上させたい場合は、代わりにキーを格納し、私がインデックスのために行った"get_cellByColumnKey"メソッドを使用することができます - あなたはサーバー上で両方を知っているので、キーメソッドはとにかくインデックスを見つけるためにそれを使用します。

オールインワンアプローチ

これは、すべてを1つのデータセルに保持する必要がある場合です。オールインワンのアプローチでは、スクリーンショットに表示されるのと同じように、チェックボックスの完全な状態を保持する 1 つのデータ列 ("EnabledOn"、"EnabledOff" など) を使用します。したがって、実際の状態を保持するチェックボックスと非表示の2つの列が再び必要になります。同様のイベント ハンドラーのセットをキューにして、クライアント側の外観と動作を提供すれば、同じように機能するソリューションが得られます。

グリッドマークアップは、必須のバインドされたフィールドとバインドされていないフィールドのバリエーションがあり、基本的には同じであり、チェックボックスの「無効化」も同じです。チェックボックスの画像ソースを確認し、編集と初期化イベントの処理をキャンセルします。主な違いは、state を設定すると完全な文字列値が処理され、保存されるという事実にあります。

// Sets the enabled/disabled state on the bound/unbound checkbox in the given cell
function SetCheckState(cell, chkState, checkStateCell) {
    try {
        var checkState = chkState? chkState.replace("Enabled", "Disabled"): "";
        var checkBoxElem = cell.get_element().getElementsByTagName("img").item(0);
        var chkStates = checkStates[checkState];
        if (!chkStates) return;
 
        // Get the default values of src and title for checkbox in its enabled state
        var enabledSrc = null, enabledTitle = null;
        if (chkState && chkState.indexOf("Enabled") >= 0) {
            enabledSrc = "ig_res/Default/" + chkStates.src.replace("disabled_", "");
            enabledTitle = chkState.replace("Enabled", "").replace("On", "Checked").replace("Off", "Unchecked");
        }
 
        cell.set_value(chkStates.value, chkStates.chkState);
        checkBoxElem.src = enabledSrc? enabledSrc : chkStates.src;
        checkBoxElem.title = enabledTitle ? enabledTitle : chkStates.title;
        checkBoxElem.alt = enabledTitle ? enabledTitle : chkStates.alt;
        checkStateCell.set_value(chkState); // Store the new checkbox state value in the corresponding hidden checkbox
    }
    catch (ex) { }
}
チェックボックスの有効/無効の状態は、文字列値を保持する非表示の列と、それらをチェックボックスに適用するロジックに基づいています

Bonus round

もちろん、このアプローチに 2 つの列が必要であると再度述べるとき、チェックボックス列を "DisabledOn" などの文字列値にバインドすることが常に効果的であるとは限らないことを意味します。しかし、それはあなたがそれをすることができないという意味ではありません。IBooleanConverter インターフェイスを使用すると、チェックボックス フィールドをバインドでき (これにより、バインドされていないオプションが自然に除外されます)、追加の非表示列が必要ないため、必要なクライアント コードも実際に簡単になります。

public class CheckboxConverter : IBooleanConverter {
  public object DefaultFalseValue {
    get {
      return "EnabledOff";
    }
  }

  public object DefaultTrueValue {
    get {
      return "EnabledOn";
    }
  }

  public bool IsFalse(object value) {
    return value.ToString().Contains("Off");
  }

  public bool IsTrue(object value) {
    return value.ToString().Contains("On");
  }
}

コンバータ処理のボーナスは、編集可能なチェックボックスがデフォルトの true/false 値を設定する場合、ユーザーがそれらと対話し、ルールを使用してチェック済みまたはチェックなしを一致させ、何も一致しない場合 ( "EnabledPartial" を参照)、実際にはチェックボックスも部分的な状態に設定することです。なんて便利でしょう!

Options, Options, Options

私はそれがまさにこのブログがあなたに提供できるものだと思います–複数の有効および無効状態チェックボックス機能を実現する3つの方法。 結合された状態を提供する 2 つのブール列が必要な場合でも、非表示列と表示列のペアを使用した 1 つの列アプローチが必要な場合でも、コンバーターを介してフィールドをバインドする場合でも、すべてのバージョンで同様の動作が生成されますが、労力と制限は異なります。どちらが要件により適しているかを判断し、デモコードをできるだけ再利用するのはあなた次第です。

コードといえば、デモ ASP.NET サイトは次のとおりです。

Visual StudioまたはWebMatrixからWebサイトとして開くと、ここから取得できるInfragistics ASP.NET がインストールされている必要があります(参照バージョンの調整が必要な場合があります)。

私はあなたの考えを聞いてみたいので、下にコメントを残すか、私にpingを送ってください@DamyanPetev

そしていつものように、あなたはTwitterで私たちをフォローすることができます@Infragistics連絡を取り合うフェイスブック,Google+のそしてLinkedInの!

デモを予約