Listitems يتم فقد السمات في القائمة المنسدلة على عون البريد؟

StackOverflow https://stackoverflow.com/questions/1313447

سؤال

أظهر لي زميل العمل هذا:

لديه قائمة هبوطية وزر على صفحة ويب. إليك الرمز وراء:

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 الموروثة للسمات الثابتة لعرضه. نأمل أن ينقذ شخص ما الوقت الذي أهدرته حتى تعثرت عليه.

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

الحل البسيط هو إضافة سمات Tooltip في 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");
        }

إذا كنت ترغب فقط في تحميل Listitems في الحمل الأول من الصفحة، فستحتاج إلى تمكين ViewState بحيث يمكن للرقابة تسلسل حالته هناك وإعادة تحميله عند عودة الصفحة.

هناك عدة أماكن حيث يمكن تمكين ViewState - تحقق من <pages/> عقدة في web.config وأيضا في <%@ page %> التوجيه في الجزء العلوي من ملف ASPX نفسه ل EnableViewState خاصية. سيحتاج هذا الإعداد إلى أن يكون true للعرض للعمل.

إذا كنت لا ترغب في استخدام ViewState، فما عليك سوى إزالة if (!IsPostBack) { ... } من حول الكود الذي يضيف ListItems وسيتم إعادة إنشاء العناصر في كل عملية عاجة.

يحرر: أعتذر - أنا أساء قراءة سؤالك. أنت صحيح أن صفات لا تبدي البقاء على قيد الحياة لأنها غير متسلسلة في ViewState. يجب عليك إعادة إضافة هذه الصفات على كل عملية عاجة.

حل واحد بسيط - استدعاء وظيفة التحميل المنسدلة الخاصة بك في أحداث click حيث تطلب إلى الوراء.

تتضمن الحلول النموذجية لهذه المشكلة إنشاء عناصر تحكم جديدة غير ممكنة تماما في الظروف العادية. هناك حل بسيط ولكنه تافه لهذه المشكلة.

القضية هي أن ListItem يفقد سماتها على إعادة النشر. ومع ذلك، فإن القائمة نفسها لا تفقد أي سمات مخصصة. يمكن للمرء الاستفادة من ذلك بطريقة بسيطة ولكنها فعالة وبالتالي.

خطوات:

  1. تسلسل سماتك باستخدام الرمز في الإجابة أعلاه (https://stackoverflow.com/a/3099755/362483.)

  2. قم بتخزينها إلى سمة مخصصة ل ListControl (القائمة المنسدلة، مربع الاختيار، أيا كان).

  3. في Post Back، اقرأ السمة المخصصة من ListControl ثم تراجعه مرة أخرى كسمات.

هنا هو الرمز الذي اعتدت عليه (DE) سمات التسلسل (ما كنت بحاجة إليه هو متابعة العناصر التي تم تقديمها في الأصل كما تم تحديدها عند الاسترجاع من الخلفية ثم حفظ الصفوف أو حذفها وفقا للتغييرات التي تم إجراؤها حسب التغييرات المستخدم على 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]);
}

(ملاحظة: لدي مكتبة تقوم بتنفيذ الأخطاء وتحويلات البيانات، حذف نفسه هنا للإيجاز).

إليك قانون VB.NET للحل الذي اقترحه لارامي ورفضه Glapman.

تحديث: الرمز الذي نشرته أدناه هو في الواقع لعنصر التحكم ListBox. فقط قم بتغيير الميراث إلى القائمة المنسدلة وإعادة تسمية الفصل.

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، إنشاء عنصر تحكم خادم جديد أو SMTH مجمع:

خلق:

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

عندما يتم تحميل الصفحة في المرة الأولى، يتم ملء القائمة، وأضيف سمة صورة ضائعة بعد إعادة النشر :( لذلك في الوقت الذي أضيف العناصر بسماته، أقوم بإنشاء مخطط جلسة واحدة "أسرة" بالإضافة إلى عدد العنصر الذي اتخذته من دورة "ل" (ستكون مثل Atte0، Attr1، Atte2، ETC ...) وفيها أحفظ قيمة السمة (المسار إلى صورة في حالتي)، عند حدوث عملية إعادة النشر (داخل " آخر ") أنا فقط حلقة القائمة وإضافة السمة المأخوذة من متغير الجلسة باستخدام" INT "لحلقة" for "وهذا هو نفسه عندما تم تحميل الصفحة (هذا لأنه في هذه الصفحة لا أقوم بإضافة عناصر إلى القائمة فقط اختيار حتى يكون لديهم دائما نفس الفهرس) ويتم تعيين السمات مرة أخرى، آمل أن يساعد هذا شخصا في المستقبل، تحياتي!

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top