2014-12-12 3 views
0

У меня есть таблица, которая создается в коде позади. В коде vb таблица заполняется на основе данных, возвращаемых из запроса, когда выбрано значение combobox. Код создает строку с двумя ячейками для метки и одну для выпадающего списка для каждой строки в данных. У меня возникли проблемы с сохранением выбранных значений выпадающего списка, которые создаются для каждой строки после обратной передачи.Сохраняющаяся динамическая таблица по обратной обратной связи

Когда таблица изначально заполнена, я храню данные в виде ViewState и воссоздаю таблицу на основе этих настроек в PageLoad. Проблема заключается в том, что каждый раз, когда я изменяю значения для раскрывающихся списков, а затем вызывается обратная передача, нажав «сохранить настройки», все настройки будут неправильно сохранены, потому что они возвращены до того, как будет вызываться даже вызов.

Я ищу, чтобы поддерживать значения по обратной стороне, но все же обновлять значения из базы данных при выборе новой учетной записи. Я попытался несколько способов сделать это и испытал две проблемы с моим кодом:

Когда у меня есть EnableViewState = "true" в таблице в разметке: Когда я выбираю элемент из выпадающего списка, чтобы выбрать новую учетную запись, выбранные значения в выпадающих списках остаются, когда они должны очищаться в это время и использовать новые значения базы данных.

Когда у меня есть EnableViewState = "false" в таблице в разметке: Любой postback сбрасывает dropdownlists в значения своих баз данных. Даже щелкнув «Сохранить», который немедленно отправляет назад, чтобы сохранить значения в базе данных, будет просто сохранять текущие значения базы данных и игнорировать выбранные значения.

код позади:

Imports System.Data.SqlClient 

Imports Telerik.Web.UI 

Public Class AccountSettings2 
    Inherits Page 

    Private _selectedAccountID As Integer 
    Protected _truckPermissions As List(Of PermissionData2) 

    Private Sub Page_Init(sender As Object, e As EventArgs) Handles Me.Init 

     _truckPermissions = New List(Of PermissionData2) 

     If Not IsNothing(Session("SelectedAccountID")) Then 
      _selectedAccountID = Session("SelectedAccountID") 
     End If 

     If Not IsPostBack Then 

      Dim dtAccounts As New DataTable("Accounts") 
      Dim col1 As DataColumn = New DataColumn() 
      col1.DataType = System.Type.GetType("System.Int32") 
      col1.ColumnName = "AccountID" 
      dtAccounts.Columns.Add(col1) 
      Dim col2 As DataColumn = New DataColumn() 
      col2.DataType = System.Type.GetType("System.String") 
      col2.ColumnName = "Name" 
      dtAccounts.Columns.Add(col2) 

      Dim row1 As DataRow 
      Dim row2 As DataRow 
      Dim row3 As DataRow 
      Dim row4 As DataRow 
      row1 = dtAccounts.NewRow() 
      row1("AccountID") = 1 
      row1("Name") = "Account 1" 
      dtAccounts.Rows.Add(row1) 
      row2 = dtAccounts.NewRow() 
      row2("AccountID") = 2 
      row2("Name") = "Account 2" 
      dtAccounts.Rows.Add(row2) 
      row3 = dtAccounts.NewRow() 
      row3("AccountID") = 3 
      row3("Name") = "Account 3" 
      dtAccounts.Rows.Add(row3) 
      row4 = dtAccounts.NewRow() 
      row4("AccountID") = 4 
      row4("Name") = "Account 4" 
      dtAccounts.Rows.Add(row4) 

      rcbAccounts.DataValueField = "AccountID" 
      rcbAccounts.DataTextField = "Name" 
      rcbAccounts.DataSource = dtAccounts 
      rcbAccounts.DataBind() 

     End If 

    End Sub 

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load 

     If Not IsPostBack Then 
      If _selectedAccountID > 0 Then 
       rcbAccounts.SelectedValue = _selectedAccountID 
       SelectAccount(_selectedAccountID) 
      End If 
     End If 

    End Sub 

#Region "UI Updates" 

    Private Sub SelectAccount(accountID As Integer) 

     _selectedAccountID = accountID 
     Session("SelectedAccountID") = accountID 
     CreateTruckPermissionsData(accountID) 

    End Sub 

    Private Sub CreateTruckPermissionsData(accessTypeID As Integer) 

     tblTruckPermissions.Rows.Clear() 

     _truckPermissions.Add(New PermissionData2(1, "Permission 1", "Permission 1", accessTypeID)) 
     _truckPermissions.Add(New PermissionData2(2, "Permission 2", "Permission 2", accessTypeID)) 
     _truckPermissions.Add(New PermissionData2(3, "Permission 3", "Permission 3", accessTypeID)) 
     _truckPermissions.Add(New PermissionData2(4, "Permission 4", "Permission 4", accessTypeID)) 
     ViewState("_truckPermissions") = _truckPermissions 

     Dim dtAccessTypes As New DataTable("AccessTypes") 
     Dim col1 As DataColumn = New DataColumn() 
     col1.DataType = System.Type.GetType("System.Int32") 
     col1.ColumnName = "AccessTypeID" 
     dtAccessTypes.Columns.Add(col1) 
     Dim col2 As DataColumn = New DataColumn() 
     col2.DataType = System.Type.GetType("System.String") 
     col2.ColumnName = "Description" 
     dtAccessTypes.Columns.Add(col2) 

     Dim row1 As DataRow 
     Dim row2 As DataRow 
     Dim row3 As DataRow 
     Dim row4 As DataRow 
     row1 = dtAccessTypes.NewRow() 
     row1("AccessTypeID") = 1 
     row1("Description") = "Type 1" 
     dtAccessTypes.Rows.Add(row1) 

     row2 = dtAccessTypes.NewRow() 
     row2("AccessTypeID") = 2 
     row2("Description") = "Type 2" 
     dtAccessTypes.Rows.Add(row2) 
     row3 = dtAccessTypes.NewRow() 
     row3("AccessTypeID") = 3 
     row3("Description") = "Type 3" 
     dtAccessTypes.Rows.Add(row3) 
     row4 = dtAccessTypes.NewRow() 
     row4("AccessTypeID") = 4 
     row4("Description") = "Type 4" 
     dtAccessTypes.Rows.Add(row4) 

     For Each pd As PermissionData2 In _truckPermissions 
      Dim tr As New TableRow() 
      Dim td As New TableCell() 
      Dim td2 As New TableCell() 
      Dim l As New Label() 
      Dim ddl As New RadDropDownList() 

      l.Text = pd.Name 
      ddl.ID = "ddlTruckPermission" + pd.ID.ToString() 
      ddl.DataTextField = "Description" 
      ddl.DataValueField = "AccessTypeID" 
      ddl.DataSource = dtAccessTypes 
      ddl.DataBind() 
      ddl.SelectedValue = pd.HasAccess 

      td.Controls.Add(l) 
      td2.Controls.Add(ddl) 
      tr.Cells.Add(td) 
      tr.Cells.Add(td2) 

      tblTruckPermissions.Rows.Add(tr) 
     Next 

    End Sub 

    Private Sub RefreshTruckSettings() 

     If _selectedAccountID = 0 Then 
      Return 
     End If 

     For Each r As TableRow In tblTruckPermissions.Rows 
      For Each c As Control In r.Cells(1).Controls 
       If c.ID.Contains("ddlTruckPermission") Then 
        Dim ddl As RadDropDownList = DirectCast(c, RadDropDownList) 

        Dim pd As PermissionData2 = _truckPermissions.Find(Function(x) x.ID = Integer.Parse(ddl.ID.Substring(0 + "ddlTruckPermission".Length, ddl.ID.Length - "ddlTruckPermission".Length))) 

        If Not IsNothing(pd) Then 
         ddl.SelectedValue = pd.HasAccess 
        End If 
       End If 
      Next 
     Next 

    End Sub 

#End Region 

#Region "Events" 

    Protected Sub btnSavePermissions_Click(sender As Object, e As EventArgs) 

     If _selectedAccountID > 0 Then 

      Dim permissionUpdates As List(Of PermissionUpdate) = New List(Of PermissionUpdate)() 

      For Each r As TableRow In tblTruckPermissions.Rows 
       For Each c As Control In r.Cells(1).Controls 
        If c.ID.Contains("ddlTruckPermission") Then 
         Dim ddl As RadDropDownList = DirectCast(c, RadDropDownList) 
         permissionUpdates.Add(New PermissionUpdate(Integer.Parse(ddl.ID.LastIndexOf("ddlTruckPermission")), False, ddl.SelectedValue)) 
        End If 
       Next 
      Next 

      ' Code to save permissions to database 

     End If 

    End Sub 

    Protected Sub rcbAccounts_SelectedIndexChanged(sender As Object, e As RadComboBoxSelectedIndexChangedEventArgs) 

     Dim newIndex As Integer 

     If (Integer.TryParse(e.Value, newIndex)) Then 
      SelectAccount(newIndex) 
     End If 

    End Sub 

#End Region 

End Class 


<Serializable> 
Public Class PermissionData2 

    Private _id As Integer 
    Private _name As String 
    Private _description As String 
    Private _hasAccess As Integer 

    Public Property ID() As Integer 

     Get 
      Return _id 
     End Get 
     Set(value As Integer) 
      _id = value 
     End Set 

    End Property 

    Public Property Name() As String 

     Get 
      Return _name 
     End Get 
     Set(value As String) 
      _name = value 
     End Set 

    End Property 

    Public Property Description() As String 

     Get 
      Return _description 
     End Get 
     Set(value As String) 
      _description = value 
     End Set 

    End Property 

    Public Property HasAccess() As Integer 

     Get 
      Return _hasAccess 
     End Get 
     Set(value As Integer) 
      _hasAccess = value 
     End Set 

    End Property 

    Public Sub New() 

     _id = 0 
     _name = Name 
     _description = Description 
     _hasAccess = 0 

    End Sub 

    Public Sub New(id As Integer, name As String, description As String, hasAccess As Integer) 

     _id = id 
     _name = name 
     _description = description 
     _hasAccess = hasAccess 

    End Sub 

End Class 

ASPX:

<%@ Page Language="vb" AutoEventWireup="false" 
    CodeBehind="AccountSettings2.aspx.vb" Inherits="AccountSettings2" %> 

<!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 id="Head1" runat="server"> 
    <link rel="stylesheet" type="text/css" href="styles/default.css" /> 
    <title>Account Settings</title> 
</head> 
<body> 
    <form id="form1" runat="server"> 

     <asp:ScriptManager runat="server" ID="ScriptManager1"></asp:ScriptManager> 

    <asp:UpdatePanel id="UpdatePanel1" runat="server" UpdateMode="Always"> 
    <ContentTemplate> 

     <telerik:RadComboBox ID="rcbAccounts" runat="server" Height="200" Width="200" 
      DropDownAutoWidth="Enabled" EmptyMessage="Select an Account" HighlightTemplatedItems="true" 
      EnableLoadOnDemand="true" Filter="Contains" 
      OnSelectedIndexChanged="rcbAccounts_SelectedIndexChanged" AutoPostBack ="true" 
      Label="Accounts: " Skin="Office2010Silver" /> 

     <asp:Table ID="tblTruckPermissions" runat="server" EnableViewState="true" /> 

     <asp:Button ID="btnSavePermissions" runat="server" Text="Save" OnClick="btnSavePermissions_Click" /> 

    </ContentTemplate> 
</asp:UpdatePanel> 

</form> 
</body> 
</html> 

ответ

0

Я нашел намного лучший способ справиться со своим сценарием. Я использовал ретранслятор, чтобы обрабатывать почти весь код, а не пытаться сделать это вручную. Я использовал http://weblogs.asp.net/infinitiesloop/TRULY-Understanding-Dynamic-Controls-_2800_Part-4_2900_, чтобы помочь мне. Спасибо Кейси Крукстон за большую помощь в работе над этим.

<asp:Repeater ID="rptTruckPermissions" runat="server" EnableViewState="true" OnItemDataBound="rptTruckPermissions_ItemDataBound"> 
          <HeaderTemplate> 
           <table> 
          </HeaderTemplate> 
          <ItemTemplate> 
           <tr> 
            <td><%# DataBinder.Eval(Container.DataItem, "PermissionName") %></td> 
            <td><telerik:RadDropDownList runat="server" ID="ddlTruckPermissionAccessTypes" /></td> 
           </tr> 
          </ItemTemplate> 
          <FooterTemplate> 
           </table> 
          </FooterTemplate> 
         </asp:Repeater> 

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load 

     If Not IsPostBack Then 

      If Not IsNothing(_accountDetails) Then 
       SelectAccount(_accountDetails.AccountID) 
      End If 

     End If 

    End Sub 

Private Sub SelectAccount(accountID As Integer) 

     _selectedAccountID = accountID 
     Session("SelectedAccountID") = accountID 

     BindTruckPermissions() 


    End Sub 

    Private Sub BindTruckPermissions() 

     rptTruckPermissions.DataSource = GetPermissionData(_selectedAccountID, PermissionCategory.Truck) 
     rptTruckPermissions.DataBind() 

    End Sub 

Protected Sub rptTruckPermissions_ItemDataBound(sender As Object, e As RepeaterItemEventArgs) 

     If e.Item.ItemType = ListItemType.Item Or e.Item.ItemType = ListItemType.AlternatingItem Then 

      Dim r As DataRowView = CType(e.Item.DataItem, DataRowView) 
      Dim ddl As RadDropDownList = CType(e.Item.FindControl("ddlTruckPermissionAccessTypes"), RadDropDownList) 
      Select Case r("PermissionTypeID") 

       Case PermissionType.LegacyBasic 
        ddl.DataSource = GetLegacyWebAccessTypes(PermissionType.LegacyBasic) 
       Case PermissionType.LegacyPublisher 
        ddl.DataSource = GetLegacyWebAccessTypes(PermissionType.LegacyPublisher) 
      End Select 

      'ddl.ID = "ddlTruckPermission" + pd.ID.ToString() 
      ddl.DataTextField = "Description" 
      ddl.DataValueField = "AccessTypeID" 
      ddl.DataBind() 

      If IsDBNull(r("AccessTypeID")) Then 
       ddl.SelectedValue = LegacyWebAccessType.NoAccess 
      Else 
       ddl.SelectedValue = r("AccessTypeID") 
      End If 

     End If 

    End Sub 
1

Хорошо, теперь, когда у меня есть взгляд на все, я очистил свой оригинальный ответ. Вот некоторые мысли:

Первый:

я бы все из метода Page_Init() и переместить его в метод Page_Load(). Page_Int() следует использовать экономно, и я не вижу достаточной причины использовать его здесь. Проблема с Page_Int() заключается в том, что он запускается слишком рано в жизненном цикле страницы до того, как большинство объектов было создано, и поэтому вы оказываетесь в странном поведении, которое трудно понять.

Я использую его только для ЛОГИКИ, который имеет отношение к странице, и должен произойти до загрузки страницы, но вы должны избегать любых действий с фактическими объектами страницы (кнопки, сетки данных и т. Д.). Я бы не использовал его здесь.

Кроме того, при использовании метода «Если не IsPostBack Then» метод Page_Int() бессмыслен, потому что он запускается только один раз перед инициализацией страницы, а затем никогда больше.

Второе:

Ok. Session ("SelectedAccountID"). Вам НУЖНО использовать переменную сеанса здесь? Переменные сеанса сохраняются на всем веб-сайте до тех пор, пока пользователь не закроет веб-сайт. Если вам нужно, чтобы это была переменная уровня сеанса (используется в другом месте на сайте, на других страницах и т. Д.), Пусть будет так.

Давайте поговорим о _selectedAccountID.Возможно ли, что сеанс («SelectedAccountID») может быть установлен где-то еще на веб-сайте перед загрузкой этой страницы? Это то, что я предполагаю, потому что Session («SelectedAccountID») является переменной Session. Я пишу код ниже этого предположения и что вы хотите использовать значение Session («SelectedAccountID»), чтобы установить начальное значение выпадающего списка.

Из-за того, что вы используете _selectedAccountID, похоже, что вы изначально заселяете его из сеанса («SelectedAccountID»). И это при изменении выпадающего списка вы хотите сбросить как _selectedAccountID, так и Session («SelectedAccountID») на выбранное значение. Это верно? Я написал код так, как если бы он был. Ниже приведен лучший способ справиться с этим.

Далее, как вы используете _truckPermissions, это немного менее понятно. Но похоже, что вам просто нужна другая переменная ViewState. Смотри ниже.

Кроме того, я хотел бы заказать все на странице в том порядке, в котором он будет называться. Итак, давайте посмотрим ....

Imports System.Data.SqlClient 
Imports Telerik.Web.UI 

Public Class AccountSettings2 
Inherits Page 

' This is your ViewState variable for selectedAccountID. You will set it first in Page_Load() inside If Not IsPostback. It can be access from any method in the code behind, and will persist across postbacks. 
Public Property _selectedAccountID() As String 
    Get 
     Return ViewState("selectedAccountID").ToString() 
    End Get 
    Set(ByVal value As String) 
     ViewState("selectedAccountID") = value 
    End Set 
End Property 

' This is your ViewState variable for truckPermissions. It can be access from any method in the code behind, and will persist across postbacks. 
Public Property _truckPermissions() As List(Of PermissionData2) 
    Get 
     Return ViewState("truckPermissions") 
    End Get 
    Set(ByVal value As List(Of PermissionData2)) 
     ViewState("truckPermissions") = value 
    End Set 
End Property 

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load 

    If Not IsPostBack Then 
     ' Anything done inside this If Then will happen ONLY when the page loads for the first time. Never again. 

     ' Set your initial value for the ViewState variable _selectedAccountID here 
     If Not IsNothing(Session("SelectedAccountID")) Then 
      _selectedAccountID = Session("SelectedAccountID") 
     Else 
      _selectedAccountID = 0 ' Do you need to give this a default value is Session("SelectedAccountID") is empty? If so, this will work. 
     End If 

     ' Create your DataTable, but to keep things easy to read inside Page_Load(), move the work to another method 
     Dim dtAccounts As DataTable = BuildDataTable() 

     ' Do this here, just to be clean 
     rcbAccounts.DataValueField = "AccountID" 
     rcbAccounts.DataTextField = "Name" 
     rcbAccounts.DataSource = dtAccounts 
     rcbAccounts.DataBind() 

     ' Set the initial value on your dropdown. 
     If _selectedAccountID > 0 Then 
      rcbAccounts.SelectedValue = _selectedAccountID 
      ' SelectAccount(_selectedAccountID) ' I don't think we want to do this here 
      CreateTruckPermissionsData(_selectedAccountID) ' But I think we DO want to do this 
     End If 

    End If 

End Sub 

Private Function BuildDataTable() As DataTable 

    Dim dtAccounts As New DataTable("Accounts") 

    dtAccounts.Columns.Add(BuildDataColumn("System.Int32", "AccountID")) 
    dtAccounts.Columns.Add(BuildDataColumn("System.String", "Name")) 

    Dim row As DataRow 
    Dim i As Integer 
    For i = 0 To 4 
     row = dtAccounts.NewRow() 
     row("AccountID") = i 
     row("Name") = "Account " & i 
     dtAccounts.Rows.Add(row) 
    Next 

    Return dtAccounts 

End Function 

Private Function BuildDataColumn(DataType As String, ColumnName As String) As DataColumn 
    Dim newCol As New DataColumn() 
    newCol.DataType = System.Type.GetType(DataType) 
    newCol.ColumnName = ColumnName 
    Return newCol 
End Function 

#Region "Events" 

Protected Sub btnSavePermissions_Click(sender As Object, e As EventArgs) 

    If _selectedAccountID > 0 Then 

     Dim permissionUpdates As List(Of PermissionUpdate) = New List(Of PermissionUpdate)() 

     For Each r As TableRow In tblTruckPermissions.Rows 
      For Each c As Control In r.Cells(1).Controls 
       If c.ID.Contains("ddlTruckPermission") Then 
        Dim ddl As RadDropDownList = DirectCast(c, RadDropDownList) 
        permissionUpdates.Add(New PermissionUpdate(Integer.Parse(ddl.ID.LastIndexOf("ddlTruckPermission")), False, ddl.SelectedValue)) 
       End If 
      Next 
     Next 

     ' Code to save permissions to database 

    End If 

End Sub 

Protected Sub rcbAccounts_SelectedIndexChanged(sender As Object, e As RadComboBoxSelectedIndexChangedEventArgs) 
    Dim newIndex As Integer 
    If (Integer.TryParse(e.Value, newIndex)) Then 
     SelectAccount(newIndex) 
    End If 
End Sub 

#End Region 



#Region "UI Updates" 

Private Sub SelectAccount(accountID As Integer) 
    _selectedAccountID = accountID 
    Session("SelectedAccountID") = accountID 
    CreateTruckPermissionsData(accountID) 
End Sub 

Private Sub CreateTruckPermissionsData(accessTypeID As Integer) 
    ' this code can be cleaned up too, like I did for building the other table. I just didn't have time to get to it. 
    tblTruckPermissions.Rows.Clear() 

    _truckPermissions.Add(New PermissionData2(1, "Permission 1", "Permission 1", accessTypeID)) 
    _truckPermissions.Add(New PermissionData2(2, "Permission 2", "Permission 2", accessTypeID)) 
    _truckPermissions.Add(New PermissionData2(3, "Permission 3", "Permission 3", accessTypeID)) 
    _truckPermissions.Add(New PermissionData2(4, "Permission 4", "Permission 4", accessTypeID)) 
    ViewState("_truckPermissions") = _truckPermissions 

    Dim dtAccessTypes As New DataTable("AccessTypes") 
    Dim col1 As DataColumn = New DataColumn() 
    col1.DataType = System.Type.GetType("System.Int32") 
    col1.ColumnName = "AccessTypeID" 
    dtAccessTypes.Columns.Add(col1) 
    Dim col2 As DataColumn = New DataColumn() 
    col2.DataType = System.Type.GetType("System.String") 
    col2.ColumnName = "Description" 
    dtAccessTypes.Columns.Add(col2) 

    Dim row1 As DataRow 
    Dim row2 As DataRow 
    Dim row3 As DataRow 
    Dim row4 As DataRow 
    row1 = dtAccessTypes.NewRow() 
    row1("AccessTypeID") = 1 
    row1("Description") = "Type 1" 
    dtAccessTypes.Rows.Add(row1) 

    row2 = dtAccessTypes.NewRow() 
    row2("AccessTypeID") = 2 
    row2("Description") = "Type 2" 
    dtAccessTypes.Rows.Add(row2) 
    row3 = dtAccessTypes.NewRow() 
    row3("AccessTypeID") = 3 
    row3("Description") = "Type 3" 
    dtAccessTypes.Rows.Add(row3) 
    row4 = dtAccessTypes.NewRow() 
    row4("AccessTypeID") = 4 
    row4("Description") = "Type 4" 
    dtAccessTypes.Rows.Add(row4) 

    For Each pd As PermissionData2 In _truckPermissions 
     Dim tr As New TableRow() 
     Dim td As New TableCell() 
     Dim td2 As New TableCell() 
     Dim l As New Label() 
     Dim ddl As New RadDropDownList() 

     l.Text = pd.Name 
     ddl.ID = "ddlTruckPermission" + pd.ID.ToString() 
     ddl.DataTextField = "Description" 
     ddl.DataValueField = "AccessTypeID" 
     ddl.DataSource = dtAccessTypes 
     ddl.DataBind() 
     ddl.SelectedValue = pd.HasAccess 

     td.Controls.Add(l) 
     td2.Controls.Add(ddl) 
     tr.Cells.Add(td) 
     tr.Cells.Add(td2) 

     tblTruckPermissions.Rows.Add(tr) 
    Next 

End Sub 


#End Region 
+0

У меня создалось впечатление, что при динамическом создании объектов в коде нужно также воссоздать их при каждом обратном обращении, это неверно? – enr4ged

+1

Нет! Не верно. В этом весь смысл ViewState. Вы создаете их один раз, когда страница загружается. Затем они сохраняются в ViewState через обратную передачу. Доверьтесь мне. Поместите это If-Then на место и посмотрите, что произойдет. Вы будете довольны результатами. Каждый метод Page_Load() на КАЖДОЙ странице должен иметь это If-Then. КАЖДЫЙ ВРЕМЯ :-) –

+0

Когда я изменяю его, чтобы включить If Not IsPostback - таблица остается пустой после каждой обратной передачи. – enr4ged

Смежные вопросы