سؤال

لقد قمت بتطوير عنصر تحكم مخصص يمتد ListBox.والفكرة هي أن عنصر التحكم "يتذكر" التعديلات التي أجريت على عناصره والتي حدثت من جانب العميل، على سبيل المثال.نتيجة لطلب AJAX.

الطريقة التي يعمل بها هي أن عنصر التحكم يعرض أيضًا إدخالاً مخفيًا، ويتم تخزين نتيجة طلب AJAX في الإدخال المخفي.يتم نشر هذا مرة أخرى، ويبحث أسلوب LoadPostData() الخاص بعنصر التحكم عن الإدخال المخفي، وإذا كان الإدخال المخفي يحتوي على بيانات، فسيقوم بإنشاء مجموعة ListItem منه.

هذا يعمل بشكل مثالي طالما أن المستخدم قام بالاختيار من مربع القائمة.إذا لم يتم ذلك، فلن يتم استدعاء الأسلوب LoadPostData()، وبالتالي لن يتم إنشاء مجموعة ListItem الجديدة.(لقد قمت بإنشاء هذا باستخدام مصحح الأخطاء.)

أفترض أنه يتم استدعاء الأسلوب LoadPostData فقط إذا كانت مجموعة بيانات POST تتضمن بيانات تتوافق مع UniqueID الخاص بعنصر التحكم (أي.سمة "الاسم" في HTML).إذا لم يقم المستخدم بإجراء تحديد من مربع القائمة، فلن يتم تضمين أي شيء في بيانات النشر الخاصة بالمعرف الفريد لمربع القائمة ولن يتم استدعاء LoadPostData().هل هذا صحيح؟

هل يمكن لأي شخص أن يقترح كيف يمكنني التأكد من أن طريقة LoadPostData() الخاصة بـ ListBox المخصصة الخاصة بي يتم استدعاؤها في كل إعادة نشر بغض النظر عما إذا كان المستخدم قد قام بالتحديد؟

شكرًا مقدمًا - أنا عالق حقًا في هذا الأمر.

ديفيد

هل كانت مفيدة؟

المحلول 3

لقد تأكدت من أنه لا يتم استدعاء الأسلوب LoadPostData() إلا إذا كانت بيانات النشر تحتوي على عنصر يحمل نفس اسم المعرف الفريد لعنصر التحكم.[يحرر:استدعاء Page.RegisterRequiresPostback أثناء Init() يتغلب على هذا.] أستطيع أن أرى السبب، لكنه مقيد تمامًا.

لقد تغلبت على المشكلة بعدم التعامل معها أثناء طريقة LoadPostData() على الإطلاق.بدلاً من ذلك، قمت بالتعامل معها بطريقة أسميها OnLoad() بدلاً من ذلك.

هناك أمران يجب مراعاتهما عند استخدام هذا الأسلوب:

1) لم يعد بإمكانك الوصول إلى كائن postCollection NameValueCollection الذي تم تمريره إلى طريقة LoadPostData() كوسيطة.هذا يعني أنه يتعين عليك استخراج بيانات النشر من مجموعة Request.Form، وهو عمل أصعب قليلًا.2) نظرًا لأن OnLoad() يحدث بعد كود معالجة ViewState، فستحتاج إلى تعيين SelectedValue يدويًا بعد إنشاء ListItems.إذا لم تقم بذلك، إذا تم ملء مربع القائمة عبر AJAX وقام المستخدم بإجراء تحديد، فسيتم فقدان التحديد.

آمل أن يساعد هذا شخص ما في المستقبل.

نصائح أخرى

لقد تأخرت قليلًا في الحديث عن هذا الأمر، ولكن، للرجوع إليها في المستقبل فقط، إليكم كيف أنجزت شيئًا مشابهًا...

عنصر التحكم الخاص بي عبارة عن شجرة تستخدم قوالب للعقد.كانت المشكلة التي كنت أتعامل معها هي كيفية التقاط التغييرات من جانب العميل على الحالة الموسعة/المنهارة للعقد.ما انتهى العمل كان:

في CreateChildControls أضف الحقل المخفي إلى مجموعة عناصر التحكم الخاصة بعنصر التحكم الجذري.

protected override int CreateChildControls(IEnumerable dataSource, bool dataBinding)
{
    ...
    _cdExpanded = new HiddenField();
    _cdExpanded.ID = "cdExpanded";
    this.Controls.Add(_cdExpanded);
    ...
}

في مكالمة OnInit

protected override void OnInit(EventArgs e)
{
    ...
    Page.RegisterRequiresPostBack(this);
    ...
}

في LoadPostData، ابحث عن قيمة في مجموعة النشر التي تطابق المعرف الفريد (وليس معرف العميل) للحقل المخفي:

public bool LoadPostData(string postDataKey, System.Collections.Specialized.NameValueCollection postCollection)
{
    ...
    string cdExpanded = postCollection[_cdExpanded.UniqueID];
    ...
}

لدي ضمن فئات العقد الفردية تعليمات برمجية تقوم بملء أحداث onclick لأزرار التبديل الخاصة بي من خلال استدعاء وظيفة JavaScript التي تأخذ معرف عنصر التحكم الأساسي والعقد الفردية كوسيطات.

    string ToggleScript
    {
        get
        {
            return "ToggleNode('" + this.ClientID + "', '" + _TreeRoot.ClientID + "');";
        }
    }
    protected override void Render(HtmlTextWriter writer)
    {
        ...
        if (this.HasChildren)
        {
            writer.AddAttribute("onclick", ToggleScript);
        }
        ...
    }

وهذا يجعل العثور على الحقل المخفي أمرًا سهلاً إلى حد ما عبر getElementById:

function ToggleNode(nodeID, treeID) {
var cdExpanded = document.getElementById(treeID + "_cdExpanded");
...
}

يقوم JavaScript بعد ذلك بتعديل قيمة الحقل المخفي حسب الحاجة للحدث الذي وقع.عندما نعود إلى الخادم، سأتمكن من تحليل محتويات هذا الحقل وتعديل حالة التحكم حسب الضرورة قبل عرضها مرة أخرى.(ملحوظة:أنا في الواقع أستخدم 3 حقول مخفية لتتبع الأحداث المختلفة ولكن المفهوم هو نفسه)

نأمل أن يساعد هذا الآخرين في المستقبل…

يبدو غريبًا جدًا أن تعمل فقط عند تحديد عنصر ما.هناك طريقة سريعة للتحقق من استدعاء LoadPostData وهي تمكين التتبع ووضع ما يلي في IPostBackDataHandler.LoadPostData(...).

Page.Trace.Write("My control", "LoadPostData");

إذا كان الأمر كذلك، فيجب عليك التأكد من حصولك على ما يلي:

Page.RegisterRequiresPostBack(this) in OnInit

هنا مراقبة عينة كاملة.

using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel.Design;
using System.ComponentModel;
using System.Web.UI.Design;

namespace Controls
{
    public sealed class ExtendedListBoxDesigner : ControlDesigner
    {

        public override string GetDesignTimeHtml()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("<div>My designer</div>");
            return sb.ToString();
        }

    }

    [DesignerAttribute(typeof(ExtendedListBoxDesigner), typeof(IDesigner))]
    public class ExtendedListBox : ListBox, INamingContainer, IPostBackDataHandler 
    {
        bool IPostBackDataHandler.LoadPostData(string postDataKey, System.Collections.Specialized.NameValueCollection postCollection)
        {
            Page.Trace.Write("ExtendedListBox", "LoadPostData");
            return true;
        }


        protected override void OnInit(EventArgs e)
        {
            Page.RegisterRequiresPostBack(this);
            base.OnInit(e);
        }

        protected override void RenderContents(HtmlTextWriter writer)
        {
            base.RenderContents(writer);
            writer.Write(string.Format("<input type=\"hidden\" name=\"{0}_dummy\" value=\"alwaysPostBack\">", this.ID));
        }

    }
}

والصفحة تبدو هكذا.

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="ControlSamlpe._Default" Trace="true" %>
<%@ Register Assembly="Controls" Namespace="Controls" TagPrefix="sample" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <sample:ExtendedListBox runat="server" ID="extListBox"></sample:ExtendedListBox>
    <asp:Button runat="server" ID="go" />
    </div>
    </form>
</body>
</html>

عند النقر فوق "انتقال"، يجب أن تشاهد "LoadPostData" في التتبع.

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