programing

DropDownList의 ListItems 특성이 포스트백 시 손실됩니까?

telecom 2023. 6. 29. 19:48
반응형

DropDownList의 ListItems 특성이 포스트백 시 손실됩니까?

동료가 보여준 것은 다음과 같습니다.

그는 드롭다운 목록과 웹 페이지의 버튼을 가지고 있습니다.뒤에 있는 코드는 다음과 같습니다.

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;
    }

페이지 로드에서는 항목의 도구 설명이 표시되지만 첫 번째 포스트백에서는 속성이 손실됩니다.왜 그럴까요, 그리고 해결 방법이 있나요?

저도 같은 문제가 있었고 작성자가 상속된 ListItem Consumer를 생성하여 ViewState의 특성을 유지하는 이 리소스에 기여하고 싶었습니다.그것이 제가 그것을 발견하기 전까지 낭비했던 시간을 누군가를 구할 수 있기를 바랍니다.

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];
            }
        }
    }
}

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

아래는 VS2008에서 Laramie의 코드를 사용하여 드롭다운 목록을 생성한 클래스 파일입니다.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/>및.config의 입니다.<%@ page %>의 맨 은 aspx 파일 자체입니다.EnableViewState소유물.이 설정은 다음과 같아야 합니다.trueViewState가 작동하도록 설정합니다.

ViewState를 ViewState를 만 하면 .if (!IsPostBack) { ... }▁that를 추가하는 코드 에서.ListItems각 포스트백에 항목이 다시 생성됩니다.

편집: 죄송합니다 - 질문을 잘못 읽었습니다.특성이 ViewState에서 직렬화되지 않았기 때문에 사후 처리에는 적용되지 않습니다.각 포스트백에서 이러한 특성을 다시 추가해야 합니다.

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

여기 VB가 있습니다.라라미가 제안하고 글렙맨이 정제한 솔루션의 순 코드입니다.

업데이트: 아래에 게시한 코드는 실제로 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 = 0
            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
                i += 1
                For Each attribute As String() In DirectCast(myState(i), String()())
                    li.Attributes(attribute(0)) = attribute(1)
                Next
            Next
        End If
    End Sub
End Class
End Namespace

이 문제에 대한 일반적인 해결책에는 일반적인 상황에서는 실현 가능하지 않은 새 컨트롤을 만드는 것이 포함됩니다.이 문제에 대한 간단하지만 사소한 해결책이 있습니다.

는 문는제입니다.ListItem포스트백에서 속성이 손실됩니다.그러나 목록 자체는 사용자 지정 특성을 잃지 않습니다.간단하면서도 효과적인 방법으로 이를 활용할 수 있습니다.

단계:

  1. 위 답변의 코드를 사용하여 속성을 직렬화합니다(https://stackoverflow.com/a/3099755/3624833) .

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

  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]);
}

(PS: 오류 처리 및 데이터 변환을 수행하는 라이브러리 함수가 있습니다. 간략화를 위해 여기서도 동일한 함수를 생략합니다.)

ViewState를 사용하지 않는 간단한 솔루션으로 새로운 서버 제어 또는 smth complex를 생성합니다.

만드는 중:

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));
        }
    }
}

@Sujay 드롭다운의 값 속성(예: csv 스타일)에 세미콜론으로 구분된 텍스트를 추가하고 String을 사용할 수 있습니다.분할(';')은 새 사용자 컨트롤을 만들지 않아도 되는 해결 방법으로 하나의 값에서 두 개의 "값"을 가져옵니다.특히 추가 속성이 거의 없고 너무 길지 않은 경우에는 더욱 그렇습니다.또한 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  

저는 세션 변수를 사용하여 제 경우 목록에 많은 요소가 포함되지 않기 때문에 잘 작동한다는 것을 달성했습니다. 이렇게 했습니다.

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" 사이클에서 가져온 요소의 수를 추가합니다(예: tr0, tr1, tr2...).) 그리고 그 안에 속성의 값(내 경우에는 이미지의 경로)을 저장합니다.포스트백이 발생할 때("else" 안에) 나는 단지 리스트를 루프하고 페이지가 로드되었을 때와 동일한 "for" 루프의 "int"를 사용하여 세션 변수에서 가져온 속성을 추가하면(이 페이지에서는 항상 동일한 인덱스를 갖도록 선택하는 것만으로 목록에 요소를 추가하지 않기 때문에) 속성이 다시 설정됩니다.이것이 미래의 누군가에게 도움이 되기를 바랍니다, 안녕하세요!

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

반응형