내용으로 건너뛰기
ASP.NET AJAX Data Grid: Enabled and Disabled 확인란 상태

ASP.NET AJAX Data Grid: Enabled and Disabled 확인란 상태

확인되어 있습니까 아니면 그렇지 않습니까? 다중 상태 확인란은 오늘 메뉴에 있습니다. 물론 "WebDataGrid는 이미 체크 박스 열을 지원하지 않습니까?".

10min read

확인되어 있습니까 아니면 그렇지 않습니까? 다중 상태 확인란은 오늘 메뉴에 있습니다. 물론 "WebDataGrid는 이미 체크 박스 열을 지원하지 않습니까?".

왜 예, tri-state CheckBox Field를 지원하지만 조금 더 유연성이 필요한 경우가 있습니다. 제품 아이디어 피드백 플랫폼에서 상기시켰듯이, 활성화 및 비활성화된 변형이 있는 더 많은 확인란 상태를 갖는 것은 사용자 자신이 직접 혜택을 받을 수 있는 것입니다. 이는 부분적으로 그리드의 편집 동작이 체크박스 필드를 대량으로 (전체 열에서와 같이) 처리하기 때문이며, 아마도 시각적 단서가 없기 때문에 열의 체크박스를 편집할 수 없기 때문일 수 있습니다. 따라서 각 행에 대해 설정할 수 있는 표준 tri-state 확인란 이상을 원하면 계속 읽으십시오. 우리가 받은 피드백을 바탕으로 팀은 솔루션을 준비했고 저도 내 스핀을 추가했으며 이를 여러분과 공유하고 싶습니다.

설정

여기에는 몇 가지 가정이 있습니다 – 확인란 열이 바인딩되거나 바인딩되지 않은 데이터 그리드를 표시하려고 하지만 편집 동작을 사용하고 각 행의 확인란이 조건 또는 다른 데이터 열에 따라 편집 가능한지 여부를 제어하려고 합니다. 이런 식으로 3개의 상태에서 enabled 및 disabled와 함께 6개로 이동하며 둘 이상의 열에 저장해야 할 수도 있습니다. 데이터 및 추가 열을 플래그, 날씨로 사용할 수 있는지 여부에 따라 확인란이 활성화되거나 전체 상태여야 합니다. 이와 같은 구현은 매우 다를 수 있으므로 약간의 조정이 필요할 수 있지만 재사용 가능한 기본 사항을 지적하고 데모 코드에서 선택적 기능을 표시하려고 합니다.

Basics

비활성화 상태를 추가하는 아이디어는 매우 영리합니다 – 체크 박스 이미지를 각각의 비활성 이미지로 바꾸고 해당 이미지에 대한 런타임 검사를 수행하여 편집을 방지합니다. 이렇게 하면 시각적 표시뿐만 아니라 감지에 사용할 수 있는 이미지 세부 정보도 제어할 수 있습니다. 따라서 3 개의 이미지가 필요하며, 경로와 값이있는 클라이언트 측의 설정 객체와 함께 확인란과 숨겨진 상태 셀 간의 매핑이 필요합니다.

처리할 클라이언트 이벤트:

  • 초기화– 추가 상태가 있는 확인란을 살펴보고 활성화/비활성화 모양을 적용합니다.
  • 편집CellValueChangeing을 처리하여 편집이 비활성화되지 않도록 합니다. 또한 API를 사용할 때 이벤트가 발생하므로 프로그래밍 방식으로 클라이언트 측에서 값을 계속 변경하려면"_set_value_internal" 메서드를 대신 사용해야 할 수도 있습니다.
  • 헤더 상자와 함께 언바운드 확인란을 사용하는 경우 HeaderCheckBoxClicked도 처리하여 적절한 상태와 값을 설정해야 합니다.

현재 데이터에서 바인딩된 필드를 사용하거나, 사용할 수 없는 경우 새 필드를 추가하거나, 플래그를 보유하는 유일한 목적으로 바인딩되지 않은 필드를 사용하거나, 클라이언트에서 실행된 논리를 기반으로 확인란을 활성화 및 비활성화할 수도 있습니다.

External Flag Approach

이것은 플래그를 기반으로 편집 가능한 상태를 적용하는 것과 함께 표준 확인란 기능을 사용합니다 - 이는 서버 로직에 의해 미리 결정되고 (un)bound 필드로 전달되거나 완전히 클라이언트 측 로직을 기반으로 하는 다른 데이터 열일 수 있습니다. 구현은 정말로 당신에게 달려 있습니다, 나는 데이터의 일부로 다른 bool 열을 사용할 것입니다 - 그리고 두 개의 체크 박스 열이 있기 때문에 마지막 두 필드에는 비활성화 된 플래그가 있습니다.

<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 함수를 사용하여 상태를 토글할 수 있으며 필요한 경우 사용자에게 다양한 방법을 제공할 수 있습니다(인접 표준 확인란 필드의 값 변경을 처리하는 데모 코드 참조).

사용 및 사용 안 함 확인란 상태는 사용자에게 숨겨지는 'flag' 보조 열(마지막 두 개)을 기반으로 합니다.

추신 : 클라이언트 설정에서 열 쌍에 대한 더 나은 가독성을 원한다면 대신 키를 저장하고 인덱스를 위해 갔던 "get_cellByColumnKey" 메소드를 사용할 수 있습니다 - 서버에서 둘 다 알고 있기 때문에 key 메소드는 어쨌든 인덱스를 찾는 데 사용합니다.

All-In-One 접근 방식

이것은 모든 것을 단일 데이터 셀에 유지해야 하는 경우에 해당합니다. 올인원(all-in-one) 접근 방식은 스크린샷에서 볼 수 있는 것처럼 확인란의 전체 상태를 문자열("EnabledOn", "EnabledOff" 등)로 유지하는 단일 데이터 열을 사용합니다. 따라서 다시 한 번 두 개의 열, 하나의 체크 박스와 실제 상태를 전달하는 숨겨진 열이 필요합니다. 클라이언트 측의 모양과 동작을 제공하기 위해 유사한 이벤트 처리기 집합을 신호로 설정하면 기능적인 솔루션을 얻을 수 있습니다.

필요한 바운드 및 언바운드 필드에 대한 변형이 있는 그리드 마크업은 본질적으로 동일하며, 이미지 소스를 확인하고 편집을 취소하고 이벤트 처리를 초기화하여 확인란을 '비활성화'하는 것도 마찬가지입니다. 가장 큰 차이점은 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) { }
}
Enabled and disabled checkbox states based on hidden column holding string values and logic applying checkboxes(체크박스에 적용되는 로직을 기반으로 하는 Enabled and disabled checkbox states)

Bonus round

물론이 방법을 위해 두 개의 열이 필요하다고 언급 할 때 확인란 열을 "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가지 방법.  결합된 상태를 제공하는 두 개의 부울 열을 원하든, 숨겨진 열 쌍과 프레젠테이션 열 쌍을 사용하거나 변환기를 통해 필드를 바인딩하는 단일 열 접근 방식을 원하든, 모든 버전은 서로 다른 노력과 제한 사항으로 유사한 동작을 생성합니다. 어느 것이 요구 사항에 더 적합한지 결정하고 가능한 한 많은 데모 코드를 재사용하는 것은 귀하에게 달려 있습니다!

코드에 대해 말하자면, 데모 ASP.NET 사이트는 다음과 같습니다.

Visual Studio 또는 WebMatrix에서 웹 사이트로 열면 여기에서 가져올 수 있는 Infragistics ASP.NET 설치해야 합니다(참조 버전 조정이 필요할 수 있음).

여러분의 생각을 듣고 싶으니 아래에 댓글을 남기거나 핑을 보내주세요@DamyanPetev.

그리고 언제나처럼 Twitter에서 저희를 팔로우할 수 있습니다@ Infragistics그리고 계속 연락하세요페이스북,구글+그리고링크드인!

데모 요청