Пользовательский серверный элемент управления устанавливает свойства по умолчанию при обратной передаче - PullRequest
2 голосов
/ 22 декабря 2011

Следуя руководству по созданию видеоплеера, я адаптировал его для создания элемента управления диапазоном HTML5.Вот мой код:

namespace CustomServerControls
{
    [DefaultProperty("Text")]
    [ToolboxData("<{0}:Range runat=server ID=Range1></{0}:Range>")]
    public class Range : WebControl
    {
        public int Min { get; set; }
        public int Max { get; set; }
        public int Step { get; set; }
        public int Value { get; set; }

        protected override void RenderContents(HtmlTextWriter output)
        {
            output.AddAttribute(HtmlTextWriterAttribute.Id, this.ID);
            output.AddAttribute(HtmlTextWriterAttribute.Width, this.Width.ToString());
            output.AddAttribute(HtmlTextWriterAttribute.Height, this.Height.ToString());

            if (Min > Max)
                throw new ArgumentOutOfRangeException("Min", "The Min value cannot be greater than the Max Value.");

            if (Value > Max || Value < Min)
                throw new ArgumentOutOfRangeException("Value", Value,
                                                      "The Value attribute can not be less than the Min value or greater than the Max value");

            if (Min != 0)
                output.AddAttribute("min", Min.ToString());

            if (Max != 0)
                output.AddAttribute("max", Max.ToString());

            if (Step != 0)
                output.AddAttribute("step", Step.ToString());

            output.AddAttribute("value", Value.ToString());

            output.AddAttribute("type", "range");
            output.RenderBeginTag("input");
            output.RenderEndTag();

            base.RenderContents(output);
        }
    }  
}

Как видите, очень простой, и он работает настолько, насколько способен задавать отдельные свойства.

Если я отправлю сообщение обратно, чтобы проверить текущее значение, элемент управления вернет свои свойства обратно к значению по умолчанию (0).Я полагаю, что это проблема состояния.Кто-нибудь видит что-то, чего мне не хватает в приведенном выше коде, чтобы заставить эту работу работать правильно?

Редактировать:

Я заметил, что эта разметка отображается на странице:

<span id="Range1" style="display:inline-block;">
    <input id="Range1" min="1" max="100" value="5" type="range">
</span>

Что, очевидно, неправильно, я не хочу, чтобы был создан тег span, а элемент управления вводом не имеет имени.Поэтому, когда я выполняю обратную передачу, я не получаю данные от элемента управления.

Ответы [ 2 ]

1 голос
/ 22 декабря 2011

Попробуйте это:

[DefaultProperty("Value")]
[ToolboxData("<{0}:Range runat=server />")]
public class Range : WebControl, IPostBackDataHandler {

    private static readonly object mChangeEvent = new object();

    public Range() : base(HtmlTextWriterTag.Input) { }

    [Category("Events")]
    public event EventHandler Change {
        add { Events.AddHandler(mChangeEvent, value); }
        remove { Events.RemoveHandler(mChangeEvent, value); }
    }

    [DefaultValue(0)]
    public int Value {
        get { return (int?)ViewState["Value"] ?? 0; }
        set { ViewState["Value"] = value; }
    }

    protected override void AddAttributesToRender(HtmlTextWriter writer) {
        base.AddAttributesToRender(writer);

        // Add other attributes (Max, Step and value)

        writer.AddAttribute(HtmlTextWriterAttribute.Value, Value.ToString());
        writer.AddAttribute(HtmlTextWriterAttribute.Name, UniqueID);
        writer.AddAttribute(HtmlTextWriterAttribute.Type, "range");
    }

    protected virtual void OnChange(EventArgs e) {
        if (e == null) {
            throw new ArgumentNullException("e");
        }

        EventHandler handler = Events[mChangeEvent] as EventHandler;

        if (handler != null) {
            handler(this, e);
        }
    }

    #region [ IPostBackDataHandler Members ]

    public bool LoadPostData(string postDataKey, NameValueCollection postCollection) {
        int val;

        if (int.TryParse(postCollection[postDataKey], out val) && val != Value) {
            Value = val;
            return true;
        }

        return false;
    }

    public void RaisePostDataChangedEvent() {
        OnChange(EventArgs.Empty);
    }

    #endregion

}

Насколько @VinayC сказал, что вы должны использовать ViewState и ControlState (для критических данных) для сохранения состояний вашего элемента управления. Кроме того, вы должны реализовать IPostBackDataHandler , чтобы восстановить последнее значение и вызвать событие изменения, как вы можете видеть в предыдущем примере.

Обновление

[DefaultProperty("Value")]
[ToolboxData("<{0}:Range runat=server />")]
public class Range : WebControl, IPostBackEventHandler, IPostBackDataHandler {

    [Category("Behavior")]
    [DefaultValue(false)]
    public bool AutoPostBack {
        get { return (bool?)ViewState["AutoPostBack"] ?? false; }
        set { ViewState["AutoPostBack"] = value; }
    }

    protected override void OnPreRender(EventArgs e) {
        base.OnPreRender(e);

        if (!DesignMode && AutoPostBack) {

            string script = @"
var r = document.getElementById('{0}');

r.addEventListener('mousedown', function (e) {{
    this.oldValue = this.value;
}});

r.addEventListener('mouseup', function (e) {{
    if (this.oldValue !== this.value) {{
        {1};
    }}
}});";

            Page.ClientScript.RegisterStartupScript(
                this.GetType(),
                this.UniqueID,
                string.Format(script, this.ClientID, Page.ClientScript.GetPostBackEventReference(new PostBackOptions(this))),
                true);
        }
    }

    #region [ IPostBackEventHandler Members ]

    public void RaisePostBackEvent(string eventArgument) {
        // If you need to do somthing on postback, derive your control 
        // from IPostBackEventHandler interface.
    }

    #endregion

}

Приведенный выше код иллюстрирует, как вы можете использовать ClientScriptManager.GetPostBackEventReference и IPostBackEventHandler для реализации простого AutoPostback для элемента управления Range.

0 голосов
/ 22 декабря 2011

Проблема заключается в том, что ваши свойства (Min, Max, Step, Value) поддерживаются полями экземпляров - в ASP.NET каждая страница и каждый экземпляр элемента управления на нем воссоздаются при создании страницы сообщения назад. Таким образом, каждый раз эти свойства будут иметь значения по умолчанию (или значения, которые вы можете установить во время разработки) - чтобы сохранить эти значения после постбека, вам необходимо поддерживать свои свойства с помощью view-state. Например:

public int Min 
{ 
   get
   {
       var value = ViewState["Min"];
       return null != value ? (int)value : 0;
   }
   set { ViewState["Min"] = value; }
}

Поскольку состояние просмотра может быть отключено, авторы элементов управления могут также использовать состояние элемента управления для резервного копирования своих важных свойств (которые необходимы для работы элемента управления) - для использования состояния элемента управления необходимо переопределить LoadControlState и SaveControlState методы.

Например (с использованием состояния управления):

public int Min { get; set; }
public int Max { get; set; }
public int Step { get; set; }
public int Value { get; set; }

protected override void OnInit(EventArgs e) 
{
    Page.RegisterRequiresControlState(this); // must for using control state
    base.OnInit(e);
}

protected override object SaveControlState() 
{
    return new int[] { Min, Max, Step, Value };
}

protected override void LoadControlState(object state) 
{
    var values = state as int[];
    if (null != values) 
    {
       Min = values[0]; Max = values[1];
       Step = values[2]; Value = values[3];
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...