Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Разработка под ASP.NET > ViewState и иерархия объектов


Автор: Idsa 25.7.2007, 15:48
Думаю, многие сталкивались с проблемой, что при динамическом создании контролов иерархия объектов должна оставаться той же, что и при предыдущем postback'е. Таким образом, если, например, заполнять PlaceHolder динамическими компонентами на основании POST-данных, может возникнуть ситуация, когда иерархия относительно предыдущего postback'а изменится. В этом случае добавление динамических контролов в коллекцию Controls приведет к исключению "Failed to load viewstate".
Данная проблема решается путем загрузки и удаления контролов из предыдущего postback'а, а только затем загрузкой нового контрола. Однако при использовании большого числа контролов такой подход становится мало того, что утомительным, да еще и очень неэффективным.
Вот, собственно, меня и интересует, есть ли более рациональные подходы для решения данной проблемы (за исключением отключения ViewState, конечно smile ).

Автор: anabiosys 21.12.2007, 13:33
Тоже столкнулся с этой проблемой. Работающего решения так и не нашёл. В msdn советуют просто отключить viewstate, до такого я и сам бы догадался, но сохранять данные вручную не очень то хочется. Кто-то с этим ещё боролся?

Автор: tol05 21.12.2007, 13:44
что-то как-то туманно. Такой сложный вопрос, да в такую рань задается!

 smile 

 Пример проблемы можно запостить?

Автор: anabiosys 21.12.2007, 14:09
В общем, в page_init есть код, который при нажатии на одну кнопку загружает в панель Control1, а при нажатии на другую - Control2. В этих контролах находятся по repeater'у, которые принимают с данные и геренерят на их основе html код и некоторые элементы управления. Так вот если мы нажмём сначала на Button1, а потом на Button2, то вылетит 'Failed to load viewstate'

Код

protected void Page_Init(object sender, EventArgs e)
{
    panel.Controls.Clear();
    if (eventTarget == lbtnButton1.UniqueID)
    {
        Controls_Control1 c = LoadControl(@"~\Controls\Control1.ascx") as Controls_Control1;
        panel.Controls.Add(c);
    }
    else if (eventTarget == lbtnButton2.UniqueID)
    {
        Controls_Control2 c = LoadControl(@"~\Controls\Control2.ascx") as Controls_Control2;
        panel.Controls.Add(c);
    }
}


Control1

Код

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="Control1.ascx.cs" Inherits="Controls_Control1" %>
<div class="table">
<div class="main-content-box">
<table>
    <tr class="first">
    <td class="image">&nbsp;</td>
    <td class="descr">Description</td>
    <td class="size">Size</td>
    <td class="location">Location</td>
    </tr>
    <asp:Repeater ID="rptrProperties" runat="server"  OnItemCommand="rptrProperties_OnItemCommand" EnableViewState="true">
             <ItemTemplate>
            <tr>
                <td class="image">
                    <div>
                        <img src="images/PropertiesImages/Icons/<%#Eval("Icon") %>" width="205" height="64" alt="><%#Eval("Title") %>" />
                        <span class="top-shadow">&nbsp;</span>

                    </div>
                </td>
                <td class="descr">
                    <div style="height:52">
                        <strong class="title"><%#Eval("Title") %></strong>
                        <p><%#Eval("Data") %></p>
                        <span><asp:LinkButton ID="lbtnProperty" runat="server" CommandName="SelectProperty" CommandArgument='<%# Eval("PropertyId") %>'>Go</asp:LinkButton></span>
                    </div>
                </td>
                <td class="size"><%#Eval("Size") %></td>
                <td class="location"><%#Eval("Location") %></td>
            </tr>
             </ItemTemplate>
         </asp:Repeater>
</table>
<span class="bot-shadow">&nbsp;</span>
<span class="top-shadow">&nbsp;</span>
<span class="right-shadow">&nbsp;</span>
<span class="left-shadow">&nbsp;</span>
</div>
</div>



Control2 наподобие, только оперирует другими данными и имеет другую структуру.

Вот как-то так...

Автор: Idsa 21.12.2007, 20:11
Ух, какое старье подняли smile
Насколько я помню, в качестве решения данной проблемы предлагается:
1. при первой (и каждой последующей) загрузке запоминать во ViewState, какой контрол был загружен
2. при постбэке сначала создать предыдущий контрол и добавить его, например, в PlaceHolder
3. очистить содержимое этого PlaceHolder'а
4. создать нужный контрол и вставить его в тот самый PlaceHolder (не забыв при это записать имя нового контрола во ViewState).

Где-то так ;)

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)