ProgramingTip

DropDownList의 ListItems 속성이 포스트 백에서 검증?

bestdevel 2020. 11. 4. 08:13
반응형

DropDownList의 ListItems 속성이 포스트 백에서 검증?


동료가 나에게 보유하고 있습니다.

그는 웹 페이지에 DropDownList와 버튼이 있습니다. 다양한 코드는 다음과 같습니다.

protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            ListItem item = new ListItem("1");
            item.Attributes.Add("title", "A");

            ListItem item2 = new ListItem("2");
            item2.Attributes.Add("title", "B");

            DropDownList1.Items.AddRange(new[] {item, item2});
            string s = DropDownList1.Items[0].Attributes["title"];
        }
    }

    protected void Button1_Click(object sender, EventArgs e)
    {
        DropDownList1.Visible = !DropDownList1.Visible;
    }

페이지로드시 항목의 툴팁이 표시되는 첫 번째 포스트 백에서는 속성이 축소됩니다. 왜 이런 경우이며 해결 방법이 있습니까?


나는 ViewState에 속성을 유지하기 위해 상속 된 ListItem Consumer를 만든 리소스 를 제공하고 싶었 습니다. 내가 그것을 우연히 발견 할 때까지 내가 사용할 수있는 시간을 절약 할 수 있기를 바랍니다.

protected override object SaveViewState()
{
    // create object array for Item count + 1
    object[] allStates = new object[this.Items.Count + 1];

    // the +1 is to hold the base info
    object baseState = base.SaveViewState();
    allStates[0] = baseState;

    Int32 i = 1;
    // now loop through and save each Style attribute for the List
    foreach (ListItem li in this.Items)
    {
        Int32 j = 0;
        string[][] attributes = new string[li.Attributes.Count][];
        foreach (string attribute in li.Attributes.Keys)
        {
            attributes[j++] = new string[] {attribute, li.Attributes[attribute]};
        }
        allStates[i++] = attributes;
    }
    return allStates;
}

protected override void LoadViewState(object savedState)
{
    if (savedState != null)
    {
        object[] myState = (object[])savedState;

        // restore base first
        if (myState[0] != null)
            base.LoadViewState(myState[0]);

        Int32 i = 1;
        foreach (ListItem li in this.Items)
        {
            // loop through and restore each style attribute
            foreach (string[] attribute in (string[][])myState[i++])
            {
                li.Attributes[attribute[0]] = attribute[1];
            }
        }
    }
}

고마워, 라라 미. 내가 찾던 바로 그것. 속성을 완벽하게 유지합니다.

확장하기 위해 아래는 Laramie의 코드를 사용하여 VS2008에서 드롭 다운 목록을 만드는 클래스 파일입니다. App_Code 폴더에 클래스를 만듭니다. 클래스를 만든 후 aspx 페이지에서 다음 줄을 사용하여 등록합니다.

<%@ Register TagPrefix="aspNewControls" Namespace="NewControls"%>

그런 다음 이것을 사용하여 웹 양식에 컨트롤을 넣을 수 있습니다.

<aspNewControls:NewDropDownList ID="ddlWhatever" runat="server">
                                                </aspNewControls:NewDropDownList>

좋아요, 여기 수업이 있습니다 ...

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Security.Permissions;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace NewControls
{
  [DefaultProperty("Text")]
  [ToolboxData("<{0}:ServerControl1 runat=server></{0}:ServerControl1>")]
  public class NewDropDownList : DropDownList
  {
    [Bindable(true)]
    [Category("Appearance")]
    [DefaultValue("")]
    [Localizable(true)]

    protected override object SaveViewState()
    {
        // create object array for Item count + 1
        object[] allStates = new object[this.Items.Count + 1];

        // the +1 is to hold the base info
        object baseState = base.SaveViewState();
        allStates[0] = baseState;

        Int32 i = 1;
        // now loop through and save each Style attribute for the List
        foreach (ListItem li in this.Items)
        {
            Int32 j = 0;
            string[][] attributes = new string[li.Attributes.Count][];
            foreach (string attribute in li.Attributes.Keys)
            {
                attributes[j++] = new string[] { attribute, li.Attributes[attribute] };
            }
            allStates[i++] = attributes;
        }
        return allStates;
    }

    protected override void LoadViewState(object savedState)
    {
        if (savedState != null)
        {
            object[] myState = (object[])savedState;

            // restore base first
            if (myState[0] != null)
                base.LoadViewState(myState[0]);

            Int32 i = 1;
            foreach (ListItem li in this.Items)
            {
                // loop through and restore each style attribute
                foreach (string[] attribute in (string[][])myState[i++])
                {
                    li.Attributes[attribute[0]] = attribute[1];
                }
            }
        }
    }
  }
}

간단한 해결책은 pre-render드롭 다운 이벤트 에서 툴팁 속성을 추가하는 것 입니다. 상태에 대한 모든 변경은 pre-render이벤트 에서 수행되어야합니다 .

샘플 코드 :

protected void drpBrand_PreRender(object sender, EventArgs e)
        {
            foreach (ListItem _listItem in drpBrand.Items)
            {
                _listItem.Attributes.Add("title", _listItem.Text);
            }
            drpBrand.Attributes.Add("onmouseover", "this.title=this.options[this.selectedIndex].title");
        }

페이지를 처음로드 할 때만 목록 항목을로드 중 하나가 해당 상태를 될화하고 페이지가 다시 게시 될 때 다시로드 할 수 있습니다 ViewState를 활성화해야합니다.

ViewState를 활성화 할 수있는 여러 위치가 있습니다 <pages/>. web.config 노드와 <%@ page %>aspx 파일 자체의 맨 위에 있는 지시문에서 EnableViewState속성을 확인하십시오. trueViewState가 작동 작동 이 설정이 필요합니다 .

ViewState를 사용하지 않는면을 if (!IsPostBack) { ... }추가하는 코드 주변에서 제거 ListItems하면 항목이 각 포스트 백에서 다시 생성됩니다.

편집 : 사과드립니다-질문을 잘못 읽었습니다. 속성 이 ViewState에서 발생 화되지 않아서 발생기 때문에 포스트 백에서 살아남지 는 것이 맞습니다 . 각 포스트 백에 해당 속성을 다시 추가해야합니다.


하나의 간단한 해결-포스트 백을 요청하는 클릭 이벤트에서 드롭 다운 로딩 기능을 호출합니다.


이 문제에 대한 해결책은 상황에서 실행 불가능한 새로운 컨트롤을 만드는 것입니다. 이 문제에 대한 간단하지만 사소한 해결책이 있습니다.

는 문제 ListItem포스트 백에서 속성 손실 된다는을 구석으로 입니다. 그러나 목록 자체는 사용자 정의 속성을 잃지 않습니다. 효과적인 방법으로 사용 가능합니다.

단계 :

  1. 위의 답변 ( https://stackoverflow.com/a/3099755/3624833 ) 의 코드를 사용하여 속성을 생성 화하십시오.

  2. ListControl의 사용자 지정 특성 (드롭 다운 목록, 체크리스트 상자 등)에 저장합니다.

  3. 다시 게시 할 때 ListControl에서 사용자 지정 특성을 다시 읽은 다음 다시 특성으로 역화합니다.

다음은 속성을 (역) 옵션 화하는 데 코드입니다 (백엔드에서 검색 할 때 목록의 추적 한 다음 변경 사항에 따라 행을 저장하거나 삭제하는 것이 필요했습니다). UI의 사용자) :

string[] selections = new string[Users.Items.Count];
for(int i = 0; i < Users.Items.Count; i++)
{
    selections[i] = string.Format("{0};{1}", Users.Items[i].Value, Users.Items[i].Selected);
}
Users.Attributes["data-item-previous-states"] = string.Join("|", selections);

(위의 "사용자"는 CheckboxList컨트롤입니다).

포스트 백 (제 경우에는 사용 가능한 버튼 클릭 이벤트)에서 아래 코드를 사용하여 동일한 항목을 검색하고 사후 처리를 위해 사전에 저장합니다.

Dictionary<Guid, bool> previousStates = new Dictionary<Guid, bool>();
string[] state = Users.Attributes["data-item-previous-states"].Split(new char[] {'|'}, StringSplitOptions.RemoveEmptyEntries);
foreach(string obj in state)
{
    string[] kv = obj.Split(new char[] { ';' }, StringSplitOptions.None);
    previousStates.Add(kv[0], kv[1]);
}

(추신 : 오류 처리 및 데이터 변환을 수행하는 라이브러리 함수가 여기서 여기서는 간결함을 위해 동일한 내용을 생략했습니다).


다음은 Laramie가 제안하고 gleapman이 개선 한 솔루션의 VB.Net 코드입니다.

업데이트 : 아래 에 게시 한 코드는 실제로 ListBox 컨트롤에 대한 것입니다. 상속을 DropDownList로 변경하고 클래스 이름을 변경하십시오.

Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Security.Permissions
Imports System.Linq
Imports System.Text
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls

Namespace CustomControls

<DefaultProperty("Text")> _
<ToolboxData("<{0}:ServerControl1 runat=server></{0}:ServerControl1>")>
Public Class PersistentListBox
    Inherits ListBox

    <Bindable(True)> _
    <Category("Appearance")> _
    <DefaultValue("")> _
    <Localizable(True)> _
    Protected Overrides Function SaveViewState() As Object
        ' Create object array for Item count + 1
        Dim allStates As Object() = New Object(Me.Items.Count + 1) {}

        ' The +1 is to hold the base info
        Dim baseState As Object = MyBase.SaveViewState()
        allStates(0) = baseState

        Dim i As Int32 = 1
        ' Now loop through and save each attribute for the List
        For Each li As ListItem In Me.Items
            Dim j As Int32 = 0
            Dim attributes As String()() = New String(li.Attributes.Count - 1)() {}
            For Each attribute As String In li.Attributes.Keys
                attributes(j) = New String() {attribute, li.Attributes(attribute)}
                j += 1
            Next
            allStates(i) = attributes
            i += 1
        Next


        Return allStates
    End Function

    Protected Overrides Sub LoadViewState(savedState As Object)
        If savedState IsNot Nothing Then
            Dim myState As Object() = DirectCast(savedState, Object())

            ' Restore base first
            If myState(0) IsNot Nothing Then
                MyBase.LoadViewState(myState(0))
            End If

            Dim i As Int32 = 1
            For Each li As ListItem In Me.Items
                ' Loop through and restore each attribute 
                ' NOTE: Ignore the first item as that is the base state and is represented by a Triplet struct
                For Each attribute As String() In DirectCast(myState(i), String()())
                    li.Attributes(attribute(0)) = attribute(1)
                    i += 1
                Next
            Next
        End If
    End Sub
End Class
End Namespace

@Sujay 드롭 다운의 값 속성 (예 : csv 스타일)에 세미콜론으로 구분 된 텍스트를 추가하고 String.Split ( ';')를 사용하여 하나의 값에서 2 개의 "값"을 얻을 수 있습니다. 새로운 사용자 컨트롤을 만들 필요가 없습니다. 특히 추가 속성이 거의없고 너무 길지 않은 경우. 드롭 다운의 값 속성에 JSON 값을 사용한 다음 거기에서 필요한 것을 파싱 할 수도 있습니다.


    //In the same block where the ddl is loaded (assuming the dataview is retrieved whether postback or not), search for the listitem and re-apply the attribute
    if(IsPostBack)
    foreach (DataRow dr in dvFacility.Table.Rows)
{                        
   //search the listitem 
   ListItem li = ddl_FacilityFilter.Items.FindByValue(dr["FACILITY_CD"].ToString());
    if (li!=null)
 {
  li.Attributes.Add("Title", dr["Facility_Description"].ToString());    
 }                  
} //end for each  

ViewState가없는 간단한 솔루션으로 새로운 서버 제어 또는 복잡한 복잡한 생성 :

생성 :

public void AddItemList(DropDownList list, string text, string value, string group = null, string type = null)
{
    var item = new ListItem(text, value);

    if (!string.IsNullOrEmpty(group))
    {
        if (string.IsNullOrEmpty(type)) type = "group";
        item.Attributes["data-" + type] = group;
    }

    list.Items.Add(item);
}

업데이트 중 :

public void ChangeItemList(DropDownList list, string eq, string group = null, string type = null)
{
    var listItem = list.Items.Cast<ListItem>().First(item => item.Value == eq);

    if (!string.IsNullOrEmpty(group))
    {
        if (string.IsNullOrEmpty(type)) type = "group";
        listItem.Attributes["data-" + type] = group;    
    }
}

예:

protected void Page_Load(object sender, EventArgs e)
{
    if (!Page.IsPostBack)
    {
        using (var context = new WOContext())
        {
            context.Report_Types.ToList().ForEach(types => AddItemList(DropDownList1, types.Name, types.ID.ToString(), types.ReportBaseTypes.Name));
            DropDownList1.DataBind();
        }
    }
    else
    {
        using (var context = new WOContext())
        {
            context.Report_Types.ToList().ForEach(types => ChangeItemList(DropDownList1, types.ID.ToString(), types.ReportBaseTypes.Name));
        }
    }
}

세션 변수를 사용하여 달성 할 수있었습니다. 제 경우에는 목록에 많은 요소가 포함되어 있지 않으므로 잘 작동합니다. 이것이 제가 한 방법입니다.

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        string[] elems;//Array with values to add to the list
        for (int q = 0; q < elems.Length; q++)
        {
            ListItem li = new ListItem() { Value = "text", Text = "text" };
            li.Attributes["data-image"] = elems[q];
            myList.Items.Add(li);
            HttpContext.Current.Session.Add("attr" + q, elems[q]);
        }
    }
    else
    {
        for (int o = 0; o < webmenu.Items.Count; o++) 
        {
            myList.Items[o].Attributes["data-image"] = HttpContext.Current.Session["attr" + o].ToString();
        }
    }
}

페이지가 처음로드 될 때 목록이 채워지고 포스트 백 후 손실되는 이미지 속성을 추가합니다. (따라서 속성이있는 요소를 추가 할 때 하나의 세션 변수 "attr"과 가져온 요소 수를 만듭니다. "for"사이클 (attr0, attr1, attr2 등이 될 것입니다 ...)에서 포스트 백이 발생할 때 속성 값 (제 경우에는 이미지 경로)을 저장합니다 ( " else ") 목록을 반복하고 페이지가로드되었을 때와 동일한"for "루프의"int "를 사용하여 Session 변수에서 가져온 속성을 추가합니다 (이 페이지에서는 요소를 추가하지 않기 때문입니다. 목록에 항상 동일한 색인을 갖도록 선택하고 속성이 다시 설정되면 앞으로 누군가에게 도움이되기를 바랍니다.

참고 URL : https://stackoverflow.com/questions/1313447/listitems-attributes-in-a-dropdownlist-are-lost-on-postback

반응형