(Flex) Flex (2011 год)

Мой первый фото-слайдер на Flex 4

>

To view this page ensure that Adobe Flash Player version 10.0.0 or greater is installed.


В начале 2011-го года я познакомился с платформой Flex и эту страничку я бы хотел посвятить своему первому Flex-компоненту. Возможно мой взгляд на веши будет полезен многим ASP.NET-программистам. Но вначале я бы хотел остановиться на теме фотослайдинга вообще и почему прочие применяемые технологии тут (как и во многих других областях) существенно уступают компоненту на Flex.


В принципе фото-слайдеры можно писать на яваскрипте самому, но врядли эта трудоемкая работа экономически эффективна. Скорее всего выгоднее использовать какой-то готовый фреймворк, чтобы облегчить кодинг. Наиболее широкоизвестных фреймворков два - JQUERY и ASP.NET AJAX. До того, как я решился сделать компонент на Flex, я писал на обоих этих фремворках.


Сначала я расскажу о своих фотосладерах на Microsoft AJAX. Такие мои фото-слайдеры вы можете увидеть например на сайте вотпуска (надеюсь они там проживут долго). Тыкнув со странички http://arenda.votpusk.ru/ в обьявление любого пользователя сайта, вы попадете на страничку описания конкретного обьекта конкретного пользователя. Внизу этой странички - несколько фоток. Тыкните в любую из них - и на страничке http://arenda.votpusk.ru/Object_foto.aspx?Object=XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX&i=Y вы попадете в мой слайдер на Microsoft AJAX.

В упрощенном виде разметка этой странички выглядит вот так:


   1:  <form id="form1" runat="server">
   2:  <div style="margin: 20px">
   3:      <asp:ScriptManager ID="ScriptManager1" runat="server">
   4:      </asp:ScriptManager>
   5:      <asp:Label ID="lKurCn" runat="server"></asp:Label><br>
   6:      <asp:HyperLink runat="server" ID="TitleHyperLink" Target="_blank">
   7:          <asp:Label ID="lTitle" runat="server" Font-Bold="True" Font-Names="Arial" Font-Size="14px"></asp:Label></asp:HyperLink>
   8:      <table style="width: 100%;" cellpadding="0" cellspacing="0">
   9:          <tr>
  10:              <td valign="top">
  11:                  <asp:UpdatePanel ID="UpdatePanel2" runat="server" RenderMode="Inline" UpdateMode="Conditional">
  12:                      <ContentTemplate>
  13:                          <asp:Label runat="server" ID="ImageTitle" CssClass="txnn"></asp:Label>
  14:                          <br>
  15:                          <br>
  16:                          <table cellpadding="0" cellspacing="0" align="left">
  17:                              <tr>
  18:                                  <td align="left" valign="top" height="30px">
  19:                                      <asp:LinkButton runat="server" ID="LinkBack1">предыдущая</asp:LinkButton>
  20:                                  </td>
  21:                                  <td valign="top">
  22:                                      <center>
  23:                                          <asp:HyperLink ID="BigImageButton" ToolTip="исходный размер" Target="_blank" runat="server"
  24:                                              ImageUrl="~/Images/lu.gif"></asp:HyperLink><asp:HyperLink ID="BigImageButton2" ToolTip="исходный размер"
  25:                                                  Target="_blank" runat="server">исходный размер</asp:HyperLink>
  26:                                      </center>
  27:                                  </td>
  28:                                  <td align="right" valign="top">
  29:                                      <asp:LinkButton ID="Link1Forward1" runat="server">следующая</asp:LinkButton>
  30:                                  </td>
  31:                              </tr>
  32:                              <tr>
  33:                                  <td align="center" valign="middle" height="560px" bgcolor="#E7E3E7" width="560px"
  34:                                      colspan="3">
  35:                                      <asp:ImageButton ID="ImageButton1" runat="server" BorderWidth="10px" BorderColor="White"
  36:                                          BorderStyle="Solid" />
  37:                                  </td>
  38:                              </tr>
  39:                          </table>
  40:                      </ContentTemplate>
  41:                      <Triggers>
  42:                          <asp:AsyncPostBackTrigger ControlID="Link1Forward1" EventName="Click" />
  43:                          <asp:AsyncPostBackTrigger ControlID="LinkBack1" EventName="Click" />
  44:                          <asp:AsyncPostBackTrigger ControlID="ImageButton1" EventName="Click" />
  45:                      </Triggers>
  46:                  </asp:UpdatePanel>
  47:              </td>
  48:              <td width="150" valign="bottom" align="right">
  49:                  <asp:Panel runat="server" ID="panFoto">
  50:                      <table width="120" cellpadding="0" cellspacing="0">
  51:                          <tr>
  52:                              <td align="center" valign="middle" height="25px" bgcolor="#E7E3E7">
  53:                                  <asp:LinkButton ID="ToRight" runat="server">
  54:                                      <asp:Image ID="Image1" runat="server" ImageUrl="Images/st_top.gif" ImageAlign="Middle">
  55:                                      </asp:Image></asp:LinkButton>
  56:                              </td>
  57:                          </tr>
  58:                          <tr>
  59:                              <td height="5px">
  60:                              </td>
  61:                          </tr>
  62:                          <tr>
  63:                              <td valign="top">
  64:                                  <asp:UpdatePanel ID="UpdatePanel1" runat="server" RenderMode="Inline" UpdateMode="Conditional">
  65:                                      <ContentTemplate>
  66:                                          <asp:DataList ID="DataList1" runat="server" DataKeyField="ID" DataMember="DefaultView"
  67:                                              CellPadding="0" HorizontalAlign="Center" RepeatColumns="1">
  68:                                              <FooterStyle Font-Bold="True" ForeColor="White" />
  69:                                              <ItemTemplate>
  70:                                                  <%--            <asp:HiddenField ID="HiddenField1" runat="server" Value='<%# Eval("ID") %>' />--%>
  71:                                                  <table cellpadding="0" cellspacing="0">
  72:                                                      <tr>
  73:                                                          <td colspan="3">
  74:                                                              <img alt="" src="http://www.imgvotpusk.ru/Images/1.gif" width="120px" height="1px" />
  75:                                                          </td>
  76:                                                      </tr>
  77:                                                      <tr>
  78:                                                          <td>
  79:                                                              <img alt="" src="http://www.imgvotpusk.ru/Images/1.gif" height="125px" width="1px" />
  80:                                                          </td>
  81:                                                          <td align="center" valign="top">
  82:                                                              <asp:UpdatePanel ID="UpdatePanel3" runat="server" RenderMode="Inline" UpdateMode="Conditional">
  83:                                                                  <ContentTemplate>
  84:                                                                      <table bgcolor="#e7e3e7" style="width: 120px; height: 120px;">
  85:                                                                          <tr>
  86:                                                                              <td valign="middle" align="center">
  87:                                                                                  <asp:ImageButton ID="SlideImageButton" runat="server" OnClick="SlideImageButton_Click" />
  88:                                                                              </td>
  89:                                                                          </tr>
  90:                                                                          </tbody>
  91:                                                                      </table>
  92:                                                                  </ContentTemplate>
  93:                                                                  <Triggers>
  94:                                                                      <asp:AsyncPostBackTrigger ControlID="SlideImageButton" EventName="Click" />
  95:                                                                  </Triggers>
  96:                                                              </asp:UpdatePanel>
  97:                                                          </td>
  98:                                                          <td>
  99:                                                              <img alt="" src="http://www.imgvotpusk.ru/Images/1.gif" height="120px" width="1px" />
 100:                                                          </td>
 101:                                                      </tr>
 102:                                                      <tr>
 103:                                                          <td colspan="3">
 104:                                                              <img alt="" src="http://www.imgvotpusk.ru/Images/1.gif" width="120px" height="1px" />
 105:                                                          </td>
 106:                                                      </tr>
 107:                                                  </table>
 108:                                              </ItemTemplate>
 109:                                              <AlternatingItemStyle HorizontalAlign="Center" VerticalAlign="Top" />
 110:                                              <ItemStyle HorizontalAlign="Center" VerticalAlign="Top" />
 111:                                              <HeaderStyle Font-Bold="True" ForeColor="White" />
 112:                                          </asp:DataList>
 113:                                      </ContentTemplate>
 114:                                      <Triggers>
 115:                                          <asp:AsyncPostBackTrigger ControlID="ToLeft" EventName="Click" />
 116:                                          <asp:AsyncPostBackTrigger ControlID="ToRight" EventName="Click" />
 117:                                      </Triggers>
 118:                                  </asp:UpdatePanel>
 119:                              </td>
 120:                          </tr>
 121:                          <tr>
 122:                              <td align="center" valign="middle" height="25px" bgcolor="#E7E3E7">
 123:                                  <asp:LinkButton ID="ToLeft" runat="server" Style="display: inline">
 124:                                      <asp:Image ID="Image2" runat="server" ImageUrl="Images/st_bot.gif"></asp:Image></asp:LinkButton>
 125:                              </td>
 126:                          </tr>
 127:                      </table>
 128:                  </asp:Panel>
 129:              </td>
 130:          </tr>
 131:      </table>
 132:      <asp:Label ID="lErr" runat="server" Text="" ForeColor="Red"></asp:Label>
 133:      <asp:SqlDataSource ID="GetObjectImages" runat="server" ConnectionString="<%$ ConnectionStrings:SQLServer_ConnectionStrings %>"
 134:          SelectCommand="select ROW_NUMBER() OVER (order by orderby,i) as [ROW_NUMBER], * from [ObjImage] with (nolock) where (ToObject=@id) and (IsModerBan is null) order by orderby">
 135:          <SelectParameters>
 136:              <asp:QueryStringParameter Name="id" Type="String" QueryStringField="Object" />
 137:          </SelectParameters>
 138:      </asp:SqlDataSource>
 139:      <asp:SqlDataSource ID="GetObjectImagesAdm" runat="server" ConnectionString="<%$ ConnectionStrings:SQLServer_ConnectionStrings %>"
 140:          SelectCommand="select ROW_NUMBER() OVER (order by orderby,i) as [ROW_NUMBER], * from [ObjImage] with (nolock) where (ToObject=@id)  order by orderby">
 141:          <SelectParameters>
 142:              <asp:QueryStringParameter Name="id" Type="String" QueryStringField="Object" />
 143:          </SelectParameters>
 144:      </asp:SqlDataSource>
 145:      <asp:SqlDataSource ID="GetObjectInfo" runat="server" ConnectionString="<%$ ConnectionStrings:SQLServer_ConnectionStrings %>"
 146:          SelectCommand="select * from [AllObjects] with (nolock) where id=@id">
 147:          <SelectParameters>
 148:              <asp:QueryStringParameter Name="id" Type="String" QueryStringField="Object" />
 149:          </SelectParameters>
 150:      </asp:SqlDataSource>
 151:  </div>
 152:  </form>

Как видите, несмотря на весь рекламный трындеж об облегчении жизни программистам с помощью AJAX - даже разметка этой странички выглядит устрашающе (хотя конечно ручная работа с AJAX в еще более простой форме выглядит еще более устрашающе). А ведь эта страничка не стоит и выеденного яйца! Просто копеечный фотосладер, прокрутчик фоток.

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


   1:   
   2:  Partial Class Object_foto
   3:      Inherits System.Web.UI.Page
   4:   
   5:      Public Property ThisTypePageLoad() As TypeOfPageLoad
   6:          Get
   7:              Return ViewState("TypePageLoad")
   8:          End Get
   9:          Set(ByVal value As TypeOfPageLoad)
  10:              ViewState("TypePageLoad") = value
  11:          End Set
  12:      End Property
  13:   
  14:      'Длина полосы с фото
  15:      Public ReadOnly Property ShowCount() As Integer
  16:          Get
  17:              Return 4
  18:          End Get
  19:      End Property
  20:   
  21:      Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
  22:          Dim ObjectChecker As New CheckContext()
  23:          ObjectChecker.CheckObjectContext(AddressOf ErrorParameters, _
  24:                                        AddressOf ObjectNotFound, _
  25:                                        AddressOf UserOwnerNotFound, _
  26:                                        AddressOf CurrUserNotFound, _
  27:                                        AddressOf ProfileNotFound, _
  28:                                        AddressOf RightToHimself, _
  29:                                        AddressOf LeftToHimself, _
  30:                                        AddressOf AdminToHimself, _
  31:                                        AddressOf AdminToLeftUser, _
  32:                                        AddressOf AdminToRightUser, _
  33:                                        AddressOf LeftToLeftUser, _
  34:                                        AddressOf RightToRightUser, _
  35:                                        AddressOf RightToLeftUser, _
  36:                                        AddressOf LeftToRightUser, _
  37:                                        AddressOf AnonToLeftUser, _
  38:                                        AddressOf AnonToRightUser)
  39:          If Not IsPostBack Then
  40:              Dim DV2 As Data.DataView
  41:              Select Case CType(ViewState("TypePageLoad"), TypeOfPageLoad)
  42:                  Case TypeOfPageLoad.AdminToHimself, TypeOfPageLoad.AdminToLeftUser, TypeOfPageLoad.AdminToRightUser, TypeOfPageLoad.LeftToHimself, TypeOfPageLoad.RightToHimself
  43:                      DV2 = GetObjectImagesAdm.Select(New DataSourceSelectArguments)
  44:                  Case TypeOfPageLoad.AnonToLeftUser, TypeOfPageLoad.AnonToRightUser, TypeOfPageLoad.LeftToRightUser, TypeOfPageLoad.LeftToLeftUser, TypeOfPageLoad.RightToRightUser, TypeOfPageLoad.RightToLeftUser
  45:                      DV2 = GetObjectImages.Select(New DataSourceSelectArguments)
  46:                  Case Else
  47:                      Exit Sub
  48:              End Select
  49:              '
  50:              If DV2 IsNot Nothing Then
  51:                  If DV2.Count > 0 Then
  52:   
  53:   
  54:                      If Request.QueryString("i") IsNot Nothing Then
  55:                          If Request.QueryString("i") <> "" Then
  56:                              EnterNum(DV2)
  57:                          Else
  58:                              DefaultNum(DV2)
  59:                          End If
  60:                      Else
  61:                          DefaultNum(DV2)
  62:                      End If
  63:                      '
  64:                      Dim DV3 As Data.DataView
  65:                      Select Case CType(ViewState("TypePageLoad"), TypeOfPageLoad)
  66:                          Case TypeOfPageLoad.AdminToHimself, TypeOfPageLoad.AdminToLeftUser, TypeOfPageLoad.AdminToRightUser, TypeOfPageLoad.LeftToHimself, TypeOfPageLoad.RightToHimself
  67:                              DV3 = GetObjectImagesAdm.Select(New DataSourceSelectArguments)
  68:                          Case Else
  69:                              DV3 = GetObjectImages.Select(New DataSourceSelectArguments)
  70:                      End Select
  71:                      '
  72:                      If DV3.Count <> 0 Then
  73:                          Dim DvShow As New Data.DataTable("Show")
  74:                          DvShow = DV3.ToTable.Clone
  75:                          For I = 0 To Math.Min(ShowCount - 1, DV3.Count - 1)
  76:                              DvShow.ImportRow(DV2.ToTable.Rows(I))
  77:                          Next
  78:                          ViewState("StartIndex") = 0
  79:                          DataList1.DataSource = DvShow
  80:                          DataList1.DataBind()
  81:                      Else
  82:                          panFoto.Enabled = False
  83:   
  84:                          panFoto.Visible = False
  85:   
  86:                      End If
  87:   
  88:                  End If
  89:              End If
  90:              '
  91:              Dim Dv1 As Data.DataView = GetObjectInfo.Select(New DataSourceSelectArguments)
  92:              If Dv1 IsNot Nothing Then
  93:                  If Dv1.Count > 0 Then
  94:                      lTitle.Text = Dv1(0)("Name") & " (" & Dv1(0)("ObjType_Name") & ")"
  95:                      lKurCn.Text = Dv1(0)("Country_Name") & " | " & Dv1(0)("Kurort_Name")
  96:                      TitleHyperLink.NavigateUrl = "Object_info_all.aspx?Object=" & Request.QueryString("Object")
  97:                      Me.Title = lTitle.Text & " | " & ImageTitle.Text
  98:                      ImageButton1.AlternateText = ImageTitle.Text
  99:                      ImageButton1.ToolTip = ImageTitle.Text
 100:                  End If
 101:              End If
 102:   
 103:   
 104:          End If
 105:      End Sub
 106:   
 107:      Sub EnterNum(ByVal DV2 As Data.DataView)
 108:          'номер рисунка конкретно указан
 109:          Dim CurrentRecordsetIndex As Integer = CInt(Request.QueryString("i"))
 110:          ViewState("CurrentRecordsetIndex") = CurrentRecordsetIndex
 111:          ImageTitle.Text = DV2(CurrentRecordsetIndex)("Name")
 112:          ImageButton1.ImageUrl = "GetFoto.ashx?id=" & DV2(CurrentRecordsetIndex)("ID").ToString & "&W=500"
 113:          BigImageButton.NavigateUrl = "GetFoto.ashx?id=" & DV2(CurrentRecordsetIndex)("ID").ToString
 114:          BigImageButton2.NavigateUrl = BigImageButton.NavigateUrl
 115:          Me.Title = lTitle.Text & " | " & ImageTitle.Text
 116:      End Sub
 117:   
 118:      Sub DefaultNum(ByVal DV2 As Data.DataView)
 119:          'номер рисунка не указан
 120:          Dim CurrentRecordsetIndex As Integer = 0
 121:          ViewState("CurrentRecordsetIndex") = 0
 122:          ImageTitle.Text = DV2(CurrentRecordsetIndex)("Name")
 123:          ImageButton1.ImageUrl = "GetFoto.ashx?id=" & DV2(CurrentRecordsetIndex)("ID").ToString & "&W=500"
 124:          BigImageButton.NavigateUrl = "GetFoto.ashx?id=" & DV2(CurrentRecordsetIndex)("ID").ToString
 125:          BigImageButton2.NavigateUrl = BigImageButton.NavigateUrl
 126:          Me.Title = lTitle.Text & " | " & ImageTitle.Text
 127:      End Sub
 128:   
 129:      Sub ErrorParameters()
 130:          lErr.Text = "Ошибка. ErrorParameters"
 131:      End Sub
 132:      Sub ObjectNotFound()
 133:          lErr.Text = "Ошибка. ObjectNotFound"
 134:      End Sub
 135:      Sub UserOwnerNotFound()
 136:          lErr.Text = "Ошибка. UserOwnerNotFound"
 137:      End Sub
 138:      Sub CurrUserNotFound()
 139:          lErr.Text = "Ошибка. CurrUserNotFound"
 140:      End Sub
 141:      Sub ProfileNotFound()
 142:          lErr.Text = "Ошибка. ProfileNotFound"
 143:      End Sub
 144:      Sub RightToHimself()
 145:          ThisTypePageLoad = TypeOfPageLoad.RightToHimself
 146:      End Sub
 147:      Sub LeftToHimself()
 148:          ThisTypePageLoad = TypeOfPageLoad.LeftToHimself
 149:      End Sub
 150:      Sub AdminToHimself()
 151:          ThisTypePageLoad = TypeOfPageLoad.AdminToHimself
 152:      End Sub
 153:      Sub AdminToLeftUser()
 154:          ThisTypePageLoad = TypeOfPageLoad.AdminToLeftUser
 155:      End Sub
 156:      Sub AdminToRightUser()
 157:          ThisTypePageLoad = TypeOfPageLoad.AdminToRightUser
 158:      End Sub
 159:      Sub LeftToLeftUser()
 160:          ThisTypePageLoad = TypeOfPageLoad.LeftToLeftUser
 161:      End Sub
 162:      Sub RightToRightUser()
 163:          ThisTypePageLoad = TypeOfPageLoad.RightToRightUser
 164:      End Sub
 165:      Sub RightToLeftUser()
 166:          ThisTypePageLoad = TypeOfPageLoad.RightToLeftUser
 167:      End Sub
 168:      Sub LeftToRightUser()
 169:          ThisTypePageLoad = TypeOfPageLoad.LeftToRightUser
 170:      End Sub
 171:      Sub AnonToLeftUser()
 172:          ThisTypePageLoad = TypeOfPageLoad.AnonToLeftUser
 173:      End Sub
 174:      Sub AnonToRightUser()
 175:          ThisTypePageLoad = TypeOfPageLoad.AnonToRightUser
 176:      End Sub
 177:   
 178:      ''' <summary>
 179:      ''' Это работает асинхронно - без полного постбека
 180:      ''' </summary>
 181:      Protected Sub ToLeft_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles ToLeft.Click
 182:          If ViewState("StartIndex") Is Nothing Then
 183:              Throw New Exception("Ошибка логики AJAX. ToLeft.Click")
 184:          End If
 185:          'запрошена прокрутка назад по рекордсету
 186:          Dim DvShow As New Data.DataTable("Show")
 187:          '
 188:          Dim DV2 As Data.DataView
 189:          Select Case CType(ViewState("TypePageLoad"), TypeOfPageLoad)
 190:              Case TypeOfPageLoad.AdminToHimself, TypeOfPageLoad.AdminToLeftUser, TypeOfPageLoad.AdminToRightUser, TypeOfPageLoad.LeftToHimself, TypeOfPageLoad.RightToHimself
 191:                  DV2 = GetObjectImagesAdm.Select(New DataSourceSelectArguments)
 192:              Case Else
 193:                  DV2 = GetObjectImages.Select(New DataSourceSelectArguments)
 194:          End Select
 195:          '
 196:          DvShow = DV2.ToTable.Clone
 197:          If DV2 IsNot Nothing Then
 198:   
 199:   
 200:              If DV2.Count > ShowCount Then
 201:                  If ViewState("StartIndex") - 1 < 0 Then
 202:                      ViewState("StartIndex") = DV2.Count - 1
 203:                  Else
 204:                      ViewState("StartIndex") = ViewState("StartIndex") - 1
 205:                  End If
 206:                  Dim I As Integer = CInt(ViewState("StartIndex"))
 207:                  While True
 208:                      DvShow.ImportRow(DV2.ToTable.Rows(I))
 209:                      If DvShow.Rows.Count >= ShowCount Then Exit While
 210:                      If I > DV2.Count - 2 Then Exit While
 211:                      I += 1
 212:                  End While
 213:                  If DvShow.Rows.Count < ShowCount Then
 214:                      For I = 0 To ShowCount - DvShow.Rows.Count - 1
 215:                          DvShow.ImportRow(DV2.ToTable.Rows(I))
 216:                      Next
 217:                  End If
 218:              Else
 219:   
 220:                  For I = 0 To DV2.Count - 1
 221:                      DvShow.ImportRow(DV2.ToTable.Rows(I))
 222:                  Next
 223:                  ViewState("StartIndex") = 0
 224:              End If
 225:              DataList1.DataSource = DvShow
 226:              DataList1.DataBind()
 227:              UpdatePanel1.Update()
 228:   
 229:          End If
 230:      End Sub
 231:   
 232:      ''' <summary>
 233:      ''' Это работает асинхронно - без полного постбека
 234:      ''' </summary>
 235:      Protected Sub ToRight_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles ToRight.Click
 236:          If ViewState("StartIndex") Is Nothing Then
 237:              Throw New Exception("Ошибка логики AJAX. ToRight.Click")
 238:          End If
 239:          'запрошена прокрутка вперед
 240:          Dim DvShow As New Data.DataTable("Show")
 241:          '
 242:          Dim DV2 As Data.DataView
 243:          Select Case CType(ViewState("TypePageLoad"), TypeOfPageLoad)
 244:              Case TypeOfPageLoad.AdminToHimself, TypeOfPageLoad.AdminToLeftUser, TypeOfPageLoad.AdminToRightUser, TypeOfPageLoad.LeftToHimself, TypeOfPageLoad.RightToHimself
 245:                  DV2 = GetObjectImagesAdm.Select(New DataSourceSelectArguments)
 246:              Case Else
 247:                  DV2 = GetObjectImages.Select(New DataSourceSelectArguments)
 248:          End Select
 249:          '
 250:          DvShow = DV2.ToTable.Clone
 251:          If DV2 IsNot Nothing Then
 252:              If DV2.Count > ShowCount Then
 253:                  If ViewState("StartIndex") + 1 < DV2.Count Then
 254:                      ViewState("StartIndex") = ViewState("StartIndex") + 1
 255:                  Else
 256:                      ViewState("StartIndex") = 0
 257:                  End If
 258:                  Dim I As Integer = CInt(ViewState("StartIndex"))
 259:                  While True
 260:                      DvShow.ImportRow(DV2.ToTable.Rows(I))
 261:                      If DvShow.Rows.Count >= ShowCount Then Exit While
 262:                      If I > DV2.Count - 2 Then Exit While
 263:                      I += 1
 264:                  End While
 265:                  If DvShow.Rows.Count < ShowCount Then
 266:                      For I = 0 To ShowCount - DvShow.Rows.Count - 1
 267:                          DvShow.ImportRow(DV2.ToTable.Rows(I))
 268:                      Next
 269:                  End If
 270:              Else
 271:                  For I = 0 To DV2.Count - 1
 272:                      DvShow.ImportRow(DV2.ToTable.Rows(I))
 273:                  Next
 274:                  ViewState("StartIndex") = 0
 275:              End If
 276:              DataList1.DataSource = DvShow
 277:              DataList1.DataBind()
 278:              UpdatePanel1.Update()
 279:   
 280:          End If
 281:      End Sub
 282:   
 283:      Protected Sub DataList1_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DataListItemEventArgs) Handles DataList1.ItemDataBound
 284:          If e.Item.DataItem IsNot Nothing Then
 285:              '
 286:              Dim CurrentUser As MembershipUser = Membership.GetUser(HttpContext.Current.User.Identity.Name)
 287:              Dim SlideImageButton As ImageButton = CType(e.Item.FindControl("SlideImageButton"), ImageButton)
 288:              SlideImageButton.AlternateText = e.Item.DataItem("Name").ToString
 289:              SlideImageButton.ToolTip = e.Item.DataItem("Name").ToString
 290:              SlideImageButton.CommandArgument = e.Item.DataItem("i")
 291:              '
 292:              Select Case CType(ViewState("TypePageLoad"), TypeOfPageLoad)
 293:                  Case TypeOfPageLoad.AdminToHimself, TypeOfPageLoad.AdminToLeftUser, TypeOfPageLoad.AdminToRightUser, TypeOfPageLoad.AdminToHimself, TypeOfPageLoad.LeftToHimself, TypeOfPageLoad.RightToHimself
 294:                      SlideImageButton.ImageUrl = "GetFoto.ashx?id=" & e.Item.DataItem("ID").ToString & "&W=100" & "&x=1"
 295:                  Case Else
 296:                      SlideImageButton.ImageUrl = "GetFoto.ashx?id=" & e.Item.DataItem("ID").ToString & "&W=100"
 297:              End Select
 298:              '
 299:          End If
 300:      End Sub
 301:   
 302:      ''' <summary>
 303:      ''' Это работает асинхронно - без полного постбека
 304:      ''' </summary>
 305:      Protected Sub Link1Forward1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Link1Forward1.Click, ImageButton1.Click
 306:          If ViewState("CurrentRecordsetIndex") Is Nothing Then
 307:              Throw New Exception("Ошибка логики AJAX. Link1Forward1_Click")
 308:          End If
 309:          Dim CurrentRecordsetIndex As Integer = ViewState("CurrentRecordsetIndex")
 310:   
 311:          Dim DV2 As Data.DataView
 312:          Select Case CType(ViewState("TypePageLoad"), TypeOfPageLoad)
 313:              Case TypeOfPageLoad.AdminToHimself, TypeOfPageLoad.AdminToLeftUser, TypeOfPageLoad.AdminToRightUser, TypeOfPageLoad.LeftToHimself, TypeOfPageLoad.RightToHimself
 314:                  DV2 = GetObjectImagesAdm.Select(New DataSourceSelectArguments)
 315:              Case TypeOfPageLoad.AnonToLeftUser, TypeOfPageLoad.AnonToRightUser, TypeOfPageLoad.LeftToRightUser, TypeOfPageLoad.LeftToLeftUser, TypeOfPageLoad.RightToRightUser, TypeOfPageLoad.RightToLeftUser
 316:                  DV2 = GetObjectImages.Select(New DataSourceSelectArguments)
 317:              Case Else
 318:                  Exit Sub
 319:          End Select
 320:   
 321:          If DV2 IsNot Nothing Then
 322:              If DV2.Count > 0 Then
 323:                  '
 324:                  If CurrentRecordsetIndex >= DV2.Count - 1 Then
 325:                      'впереди по рекордсету рисунков уже нет
 326:                      ViewState("CurrentRecordsetIndex") = 0
 327:                  Else
 328:                      ViewState("CurrentRecordsetIndex") = CurrentRecordsetIndex + 1
 329:                  End If
 330:                  '
 331:                  ImageTitle.Text = DV2(ViewState("CurrentRecordsetIndex"))("Name")
 332:                  ImageButton1.ImageUrl = "GetFoto.ashx?id=" & DV2(ViewState("CurrentRecordsetIndex"))("ID").ToString & "&W=500"
 333:                  BigImageButton.NavigateUrl = "GetFoto.ashx?id=" & DV2(ViewState("CurrentRecordsetIndex"))("ID").ToString
 334:                  BigImageButton2.NavigateUrl = BigImageButton.NavigateUrl
 335:                  Me.Title = lTitle.Text & " | " & ImageTitle.Text
 336:                  '
 337:              End If
 338:          End If
 339:          UpdatePanel2.Update()
 340:      End Sub
 341:   
 342:      ''' <summary>
 343:      ''' Это работает асинхронно - без полного постбека
 344:      ''' </summary>
 345:      Protected Sub LinkBack1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles LinkBack1.Click
 346:          If ViewState("CurrentRecordsetIndex") Is Nothing Then
 347:              Throw New Exception("Ошибка логики AJAX. LinkBack1_Click")
 348:          End If
 349:          Dim CurrentRecordsetIndex As Integer = ViewState("CurrentRecordsetIndex")
 350:   
 351:          Dim DV2 As Data.DataView
 352:          Select Case CType(ViewState("TypePageLoad"), TypeOfPageLoad)
 353:              Case TypeOfPageLoad.AdminToHimself, TypeOfPageLoad.AdminToLeftUser, TypeOfPageLoad.AdminToRightUser, TypeOfPageLoad.LeftToHimself, TypeOfPageLoad.RightToHimself
 354:                  DV2 = GetObjectImagesAdm.Select(New DataSourceSelectArguments)
 355:              Case TypeOfPageLoad.AnonToLeftUser, TypeOfPageLoad.AnonToRightUser, TypeOfPageLoad.LeftToRightUser, TypeOfPageLoad.LeftToLeftUser, TypeOfPageLoad.RightToRightUser, TypeOfPageLoad.RightToLeftUser
 356:                  DV2 = GetObjectImages.Select(New DataSourceSelectArguments)
 357:              Case Else
 358:                  Exit Sub
 359:          End Select
 360:   
 361:          If DV2 IsNot Nothing Then
 362:              If DV2.Count > 0 Then
 363:                  If CurrentRecordsetIndex = 0 Then
 364:                      'сзади по рекордсету рисунков уже нет
 365:                      ViewState("CurrentRecordsetIndex") = DV2.Count - 1
 366:                  Else
 367:                      ViewState("CurrentRecordsetIndex") = CurrentRecordsetIndex - 1
 368:                  End If
 369:                  '
 370:                  ImageTitle.Text = DV2(ViewState("CurrentRecordsetIndex"))("Name")
 371:                  ImageButton1.ImageUrl = "GetFoto.ashx?id=" & DV2(ViewState("CurrentRecordsetIndex"))("ID").ToString & "&W=500"
 372:                  BigImageButton.NavigateUrl = "GetFoto.ashx?id=" & DV2(ViewState("CurrentRecordsetIndex"))("ID").ToString
 373:                  BigImageButton2.NavigateUrl = BigImageButton.NavigateUrl
 374:                  Me.Title = lTitle.Text & " | " & ImageTitle.Text
 375:              End If
 376:          End If
 377:          UpdatePanel2.Update()
 378:      End Sub
 379:   
 380:      ''' <summary>
 381:      ''' Это работает асинхронно - без полного постбека
 382:      ''' </summary>
 383:      Protected Sub SlideImageButton_Click(ByVal sender As Object, ByVal e As System.Web.UI.ImageClickEventArgs)
 384:          Dim SlideImageButton As ImageButton = CType(sender, ImageButton)
 385:          Dim DV2 As Data.DataView
 386:          Select Case CType(ViewState("TypePageLoad"), TypeOfPageLoad)
 387:              Case TypeOfPageLoad.AdminToHimself, TypeOfPageLoad.AdminToLeftUser, TypeOfPageLoad.AdminToRightUser, TypeOfPageLoad.LeftToHimself, TypeOfPageLoad.RightToHimself
 388:                  DV2 = GetObjectImagesAdm.Select(New DataSourceSelectArguments)
 389:              Case TypeOfPageLoad.AnonToLeftUser, TypeOfPageLoad.AnonToRightUser, TypeOfPageLoad.LeftToRightUser, TypeOfPageLoad.LeftToLeftUser, TypeOfPageLoad.RightToRightUser, TypeOfPageLoad.RightToLeftUser
 390:                  DV2 = GetObjectImages.Select(New DataSourceSelectArguments)
 391:              Case Else
 392:                  Exit Sub
 393:          End Select
 394:   
 395:          If DV2 IsNot Nothing Then
 396:              If DV2.Count > 0 Then
 397:                  For i = 0 To DV2.Count - 1
 398:                      If DV2(i)("i") = SlideImageButton.CommandArgument Then
 399:                          ViewState("CurrentRecordsetIndex") = i
 400:                          ImageTitle.Text = DV2(i)("Name")
 401:                          Me.Title = lTitle.Text & " | " & ImageTitle.Text
 402:                          ImageButton1.ImageUrl = "GetFoto.ashx?id=" & DV2(i)("ID").ToString & "&W=500"
 403:                          BigImageButton.NavigateUrl = "GetFoto.ashx?id=" & DV2(i)("ID").ToString
 404:                          BigImageButton2.NavigateUrl = BigImageButton.NavigateUrl
 405:                          UpdatePanel2.Update()
 406:                      End If
 407:                  Next
 408:   
 409:              End If
 410:          End If
 411:   
 412:      End Sub
 413:     
 414:  End Class

Вот так облегчение придумали нам c ASP.NET AJAX! Причем я написал эту страничку столь компактно, насколько это было возможно! Извращался как мог для упрощения - калбеками например (строки 129-188 - в них производится модификация операций, выполняемой базовой страничкой. CallBack - это ассемблерная терминология, в терминологии бейсика - это делегаты). Все же основные операции странички вынесены в базовую страничку - этими кальеками лишь иногда слегка модифицируюся операции базовой странички. Но на код УЖЕ страшно смотреть. А страничка, страничка-то ведь какая копеечная!

Есть некий альтернативный подход - с JQUERY. Его вы тоже можете увидеть на титуле Вотпуска. Программирование в JQUERY выглядит на порядок проще (если не считать необходимость глубокого понимания JQUERY). Даже на уровне разметки все выглядит гораздо приличнее.


   1:      <table cellspacing="0" cellpadding="0" border="0" width="100%" class="listing_media">
   2:          <tbody>
   3:              <tr>
   4:                  <td nowrap="" align="left" width="16px" style="padding-top: 4px;">
   5:                      <a target="_new" href="#" style="" id="aleft_foto">
   6:                          <img height="120px" border="0" width="16px" alt="" src="http://www.votpusk.ru/images/s_left.gif">
   7:                      </a>
   8:                  </td>
   9:                  <td class="list">
  10:                      <div class="oh">
  11:                          <div class="oh2">
  12:                              <table cellspacing="0" cellpadding="0" align="center" width="100%" id="acont_foto"
  13:                                  style="margin-left: 0pt;">
  14:                                  <tbody>
  15:                                      <tr>
  16:                                          <td>
  17:                                              <div align="center" class="item" style="width: 122.2px;">
  18:                                                  <div class="item2">
  19:                                                      <p style="padding: 0pt; margin: 0pt;">
  20:                                                          <a target="_new" href="http://foto.votpusk.ru/foto_slide.aspx?i=B0358B2C-FB56-45C9-A889-E0C7614F8F2E&amp;j=741A036B9764B3B448D08E528441ACA5F76C">
  21:                                                              <img style="border: 1px outset rgb(0, 0, 0);" alt="" src="http://foto.votpusk.ru/GetImage.ashx?j=741A036B9764B3B448D08E528441ACA5F76C&amp;w=100"></a></p>
  22:                                                  </div>
  23:                                              </div>
  24:                                          </td>
  25:                                          <td>
  26:                                              <div align="center" class="item" style="width: 122.2px;">
  27:                                                  <div class="item2">
  28:                                                      <p style="padding: 0pt; margin: 0pt;">
  29:                                                          <a target="_new" href="http://foto.votpusk.ru/foto_slide.aspx?i=B0358B2C-FB56-45C9-A889-E0C7614F8F2E&amp;j=548643D4BB6A50FEEA19F58AD8D93BABF76C">
  30:                                                              <img style="border: 1px outset rgb(0, 0, 0);" alt="" src="http://foto.votpusk.ru/GetImage.ashx?j=548643D4BB6A50FEEA19F58AD8D93BABF76C&amp;w=100"></a></p>
  31:                                                  </div>
  32:                                              </div>
  33:                                          </td>
  34:                                          <td>
  35:                                              <div align="center" class="item" style="width: 122.2px;">
  36:                                                  <div class="item2">
  37:                                                      <p style="padding: 0pt; margin: 0pt;">
  38:                                                          <a target="_new" href="http://foto.votpusk.ru/foto_slide.aspx?i=B0358B2C-FB56-45C9-A889-E0C7614F8F2E&amp;j=91CB41DC4F8962BE04DECA005191382FF76C">
  39:                                                              <img style="border: 1px outset rgb(0, 0, 0);" alt="" src="http://foto.votpusk.ru/GetImage.ashx?j=91CB41DC4F8962BE04DECA005191382FF76C&amp;w=100"></a></p>
  40:                                                  </div>
  41:                                              </div>
  42:                                          </td>
  43:                                          <td>
  44:                                              <div align="center" class="item" style="width: 122.2px;">
  45:                                                  <div class="item2">
  46:                                                      <p style="padding: 0pt; margin: 0pt;">
  47:                                                          <a target="_new" href="http://foto.votpusk.ru/foto_slide.aspx?i=B0358B2C-FB56-45C9-A889-E0C7614F8F2E&amp;j=CF89E4E80527BC3EACFBDBB87DD76314F76C">
  48:                                                              <img style="border: 1px outset rgb(0, 0, 0);" alt="" src="http://foto.votpusk.ru/GetImage.ashx?j=CF89E4E80527BC3EACFBDBB87DD76314F76C&amp;w=100"></a></p>
  49:                                                  </div>
  50:                                              </div>
  51:                                          </td>
  52:                                          <td>
  53:                                              <div align="center" class="item" style="width: 122.2px;">
  54:                                                  <div class="item2">
  55:                                                      <p style="padding: 0pt; margin: 0pt;">
  56:                                                          <a target="_new" href="http://foto.votpusk.ru/foto_slide.aspx?i=B0358B2C-FB56-45C9-A889-E0C7614F8F2E&amp;j=76941513E4451DA248EF22046B9383CDF76C">
  57:                                                              <img style="border: 1px outset rgb(0, 0, 0);" alt="" src="http://foto.votpusk.ru/GetImage.ashx?j=76941513E4451DA248EF22046B9383CDF76C&amp;w=100"></a></p>
  58:                                                  </div>
  59:                                              </div>
  60:                                          </td>
  61:                                      </tr>
  62:                                  </tbody>
  63:                              </table>
  64:                          </div>
  65:                      </div>
  66:                  </td>
  67:                  <td nowrap="" align="right" width="22px" style="padding-top: 4px;">
  68:                      <a target="_new" href="#" style="" id="aright_foto">
  69:                          <img height="120px" border="0" width="16px" alt="" src="http://www.votpusk.ru/images/s_right.gif">
  70:                      </a>
  71:                  </td>
  72:              </tr>
  73:          </tbody>
  74:      </table>
  75:   
  76:  <script type="text/javascript">
  77:  //<![CDATA[
  78:      aslider.get('foto').items = 5;
  79:      aslider.get('foto').itemWidth = 116;
  80:      aslider.get('foto').mixData = true;
  81:      aslider.get('foto').data = [
  82:  ['http://foto.votpusk.ru/foto_slide.aspx?i=B0358B2C-FB56-45C9-A889-E0C7614F8F2E&j=07659DC409352E8EF66FC5B85591575DF76C', 'http://foto.votpusk.ru/GetImage.ashx?j=07659DC409352E8EF66FC5B85591575DF76C&w=100'],
  83:  ['http://foto.votpusk.ru/foto_slide.aspx?i=15BDE1C6-F956-4646-AC45-C6DE0D788D30&j=1D59EAC4182232CBAE02F20768D3C055F76C', 'http://foto.votpusk.ru/GetImage.ashx?j=1D59EAC4182232CBAE02F20768D3C055F76C&w=100'],
  84:  ['http://foto.votpusk.ru/foto_slide.aspx?i=B0358B2C-FB56-45C9-A889-E0C7614F8F2E&j=F0A606B6B46BD48B3B45AEE3D54F4E22F76C', 'http://foto.votpusk.ru/GetImage.ashx?j=F0A606B6B46BD48B3B45AEE3D54F4E22F76C&w=100'],
  85:  ['http://foto.votpusk.ru/foto_slide.aspx?i=B0358B2C-FB56-45C9-A889-E0C7614F8F2E&j=0350B95F150992F01D1CFBD7E005E83DF76C', 'http://foto.votpusk.ru/GetImage.ashx?j=0350B95F150992F01D1CFBD7E005E83DF76C&w=100'],
  86:  ['http://foto.votpusk.ru/foto_slide.aspx?i=B0358B2C-FB56-45C9-A889-E0C7614F8F2E&j=A2AC3B2EC98609143025DB6E20D5D945F76C', 'http://foto.votpusk.ru/GetImage.ashx?j=A2AC3B2EC98609143025DB6E20D5D945F76C&w=100'],
  87:  ['http://foto.votpusk.ru/foto_slide.aspx?i=B0358B2C-FB56-45C9-A889-E0C7614F8F2E&j=F105E7904B7862AF0F4EB67D5DBFBAAEF76C', 'http://foto.votpusk.ru/GetImage.ashx?j=F105E7904B7862AF0F4EB67D5DBFBAAEF76C&w=100'],
  88:  ['http://foto.votpusk.ru/foto_slide.aspx?i=B0358B2C-FB56-45C9-A889-E0C7614F8F2E&j=52D5C12F43096609C3B7934B9AFB2907F76C', 'http://foto.votpusk.ru/GetImage.ashx?j=52D5C12F43096609C3B7934B9AFB2907F76C&w=100'],
  89:  ['http://foto.votpusk.ru/foto_slide.aspx?i=B0358B2C-FB56-45C9-A889-E0C7614F8F2E&j=741A036B9764B3B448D08E528441ACA5F76C', 'http://foto.votpusk.ru/GetImage.ashx?j=741A036B9764B3B448D08E528441ACA5F76C&w=100'],
  90:  ['http://foto.votpusk.ru/foto_slide.aspx?i=B0358B2C-FB56-45C9-A889-E0C7614F8F2E&j=76941513E4451DA248EF22046B9383CDF76C', 'http://foto.votpusk.ru/GetImage.ashx?j=76941513E4451DA248EF22046B9383CDF76C&w=100'],
  91:  ['http://foto.votpusk.ru/foto_slide.aspx?i=B0358B2C-FB56-45C9-A889-E0C7614F8F2E&j=548643D4BB6A50FEEA19F58AD8D93BABF76C', 'http://foto.votpusk.ru/GetImage.ashx?j=548643D4BB6A50FEEA19F58AD8D93BABF76C&w=100'],
  92:  ['http://foto.votpusk.ru/foto_slide.aspx?i=B0358B2C-FB56-45C9-A889-E0C7614F8F2E&j=602F60803EC8FBF23E6CC740B184F9E3F76C', 'http://foto.votpusk.ru/GetImage.ashx?j=602F60803EC8FBF23E6CC740B184F9E3F76C&w=100'],
  93:  ['http://foto.votpusk.ru/foto_slide.aspx?i=B0358B2C-FB56-45C9-A889-E0C7614F8F2E&j=3E7143DD0025C28AEA488F7581A751EBF76C', 'http://foto.votpusk.ru/GetImage.ashx?j=3E7143DD0025C28AEA488F7581A751EBF76C&w=100'],
  94:  ['http://foto.votpusk.ru/foto_slide.aspx?i=B0358B2C-FB56-45C9-A889-E0C7614F8F2E&j=CF89E4E80527BC3EACFBDBB87DD76314F76C', 'http://foto.votpusk.ru/GetImage.ashx?j=CF89E4E80527BC3EACFBDBB87DD76314F76C&w=100'],
  95:  ['http://foto.votpusk.ru/foto_slide.aspx?i=B0358B2C-FB56-45C9-A889-E0C7614F8F2E&j=91CB41DC4F8962BE04DECA005191382FF76C', 'http://foto.votpusk.ru/GetImage.ashx?j=91CB41DC4F8962BE04DECA005191382FF76C&w=100'],
  96:  ['http://foto.votpusk.ru/foto_slide.aspx?i=B0358B2C-FB56-45C9-A889-E0C7614F8F2E&j=301CE3B19EB22CC934968CFC6FF3E6A2F76C', 'http://foto.votpusk.ru/GetImage.ashx?j=301CE3B19EB22CC934968CFC6FF3E6A2F76C&w=100'],
  97:  ];
  98:      aslider.get('foto').init();
  99:  //]]>
 100:  </script>

Вроде при этом подходе есть небольшое облегчение программирования. Как видите - тут просто вызов проги http://www.votpusk.ru/java_script/slider.js. Но на эту прогу даже смотреть страшно - это миллионы строк кода. И что мы наблюдаем в итоге? 211 реквестов к серверу и страничку весом более мегабайта (из которых 157 килобайт (15%) занимает только загрузка этой адской проги slider.js на миллион строк кода:




При этом данная прога на JQUERY даже не работает в Web-сервисом и не читает реально самые топовые фотки из базы - как в моем первом фрагменте на MS AJAX. Чтобы прикрутить сюда считывание реально лучшего контента сайта - придется немного повозиться. Для начала надо сделать Web-сервис, который будет выдавать результат в формате JSON (в ASP.NET 2 предустановленного шаблона для такого сервиса нет, только в ASP.NET 4), потом на страничке Язваскриптом принять и распарсить JSON функций $.getJSON. И лишь потом сформировать вызовы aslider.


Остановимся и призадумаемся. У нас есть миллион строк исходного текста на JAVASCRIPT, который надо медленно-медленно в один поток интерпритировать браузером. Что для этого нужно? Адская мощность процессора и разрешение на интерпритацию.

На моем мощном девелоперском кампе при зажатии кнопки прокрутки фото-слайдера на JQUERY процессор сразу улетает в 100%. Жаль у меня нет более дохлого кампутера - выполнится ли эта прокрутка вообще?




И второй еще более важный момент - работа JQUERY (как и любого JAVASRIPT) должна быть специально разрешена. Причем даже для трастовой зоны!




Вот так технология, едрить в коромысло! Или самому сломать себе мозг на MS AJAX, или вызвать миллион строк чужого кода, прочитать 157 килобайт каждый раз и при КАЖДОМ рефреше проинтерпритировать весь этот миллион строк кода (начиная с прохода лексического анализатора). Да еще и разрешение должно быть специальное выставлено в браузере чтобы это все работало!




Дело еще и в том, что разработка ASP.NET, увы, так и не была доведена до конца и однажды сделанный визуальный контрол нельзя вырезать на страничке нажать кнопочку Save as dll и навсегда для себя сохранить это решение (разметку и алгоритмы под этой разметкой). То есть прогу на ASP.NET надо КАЖДЫЙ раз писать заново. Есть некие возможности по распространения DLL с сайтами на ASP.NET (вот например моя публично распространяемая DLL с целым ASP.NET-сайтом), но этот способ не касается отдельных контролов, которые все равно надо готовить вручную (вообще без дизафнера). И при всяком применении контрола все равно увязывать структуру постбеков контрола со структурой постбеков самой странички. А этого-то как раз так не хочется делать!

Все ожидали, что разработка ASP.NET будет доведена хотя бы до состояния шестого бейсика (1996-1998 годов). В Бейсике мы могли выделять любой фрагмент любой формы, нажал одну кнопку и вуаля - этот фрагмент оказывался сохраненным в файле OCX. И в дальнейшем в любом проекте можно было просто drag-and-drop'ом перетащить этот OCX на любую форму и этот OCX работал без малейших доработок и воспоминаний что в нем было внутри. Любой следующий проект можно было строить из своих предыдущих наработок. Когда в 2002-м году появилась ASP.NET 1.1 она была настолько ублюдочной, что падала раз по двадцать на дню. Всем стало понятно, что это только некий промежуточный вариант. Все стали ждать NET 2.0, надеясь что в нем доведут ASP.NET до нужной кондиции. Однако в NET 2.0 только выбрали баги, добавили Generic-коллекции и наконец-то доделали визуальный редактор DataSet (с ADO.NET наконец-то стало удобно работать). Все стали ждать выхода следующей версии - но там оказалась полнейшая и никому не нужная ерунда - WCF, перенесли библиотеку AJAX из дополнительных компонентов на панель инструментов, малоценный LINQ и прочая чушь. Половина ASP.NET программистов, которая все это осознала - сразу ушла на Яву. Я тоже как только увидел NET 3.5 - тоже поставил себе NetBeans и решил задачку на Яве (надо собраться с силами и описать ее когда-нибудь). А потом MS вообще аббалдела - наняла бригаду индусов, которые вообще никогда не слышали об ASP.NET и заказала им делать ASP.NET MVC и распространять со своего сайта PHP. ASP.NET программисты стали разбегаться кто-куда и рынок, занимаемый ASP.NET сократился до 0,4% от общего рынка web-приложений. После того, как я увидел, что именно сделали в NET 4.0 - я ужаснулся. Там оказался какой-то безумный Entity Framework (хотя для работы с PosrgreSQL нужна лишь крошечная обертка на 20 строчек сохраняющая Singlton-коннект, а для работы с MySQL не нужно вообще ничего, кроме провайдра/драйвера СУБД) и ни к селу ни к городу прикрученный к ядру ASP.NET UrlRewriting (который и так в любой момент бепрепятственно можно было добавить к любому ASP.NET приложению в виде OpenSource-библиотеки). Тут по-моему не выдержали нервы даже у самых стойких асперов. Когда я 2005-м году переходил с первого на второй фреймворк ASP.NET, я сидел на форуме SQL.Ru и задавал там вопросы по второму фреймворку (ну и отвечал иногда тоже). В день в разделе ASP.NET крутились сотни, иногда даже тысячи обсуждаемых вопросов. И в разделе форума про ASP.NET крутились десятки тысяч проггеров. Когда я в 2010-м году что-то спросил на том же форуме про какую-то очередную ублюдочную индустскую придумку Castle из MVC - мой вопрос так и оставался единственным в течении недели. Иначе говоря, людей в разделе ASP.NET на всех форумах просто не стало. И это несмотря на адскую пропадаганду микрософта и даже несмотря на то, что - как я писал об этом не раз - именно микрософтовкие проги изучаются в школе начиная с третьего класса (и без знания их даже не выдается аттестат зрелости).


Что же делать? Работать-то как-то надо. И так хочется иметь для сайта откомпилированный компонент, который бы удовлетворял самым элементарным требованиям:

С некоторой натяжкой можно считать что и JAVA-аплеты являются удовлетворяющей этим элементарным требованиям технологией. Однако небольшие размышления о возможностях графических и анимационных приводят к пониманию преимуществ Flex-платформы. Тем более Флеш-плеер установлен у 99,1% пользователей интернета, что существенно превышает процент пользователей у которых установлена и нормально работает JRE-машина.

Вот так, собственно я пришел к полезности Flex-программирования для Web-платформы - Знакомство с Adobe Flex 4. Смешно, но получается, что Adobe реализовала многие ожидания программистов, которые ждали-ждали реализации вышеперечисленных элементарных возможностей от билогейтсовской империи, да так и не дождались.

Ниже описанный автономный компонет, как вы понимаете, может быть размещен на страничке, сделанной на любой серверной технологии, от PHP и JAVA до ASP.NET и ASP.NET MVC.




Итак, перейдем наконец к рассмотрению моего кода на Flex. Это код того же самого фото-слайдера, который перед этим был уже дважды описан выше на технологиях JQUERY и MS AJAX. И вот как выглядит этот же фотослайдер на Flex (прошу строго не судить - это моя первая проба пера на Flex):


   1:  <?xml version="1.0" encoding="utf-8"?>
   2:  <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
   3:                 xmlns:s="library://ns.adobe.com/flex/spark" 
   4:                 xmlns:mx="library://ns.adobe.com/flex/mx"
   5:                 applicationComplete="application1_applicationCompleteHandler(event)" 
   6:                 minWidth.Image_Load="740" minHeight.Image_Load="125" 
   7:                 width.Image_Load="740" height.Image_Load="125" 
   8:                 minWidth.Debug="500" minHeight.Debug="500" >
   9:      
  10:      <fx:Script>
  11:          
  12:          <![CDATA[
  13:              import flash.net.navigateToURL;
  14:              import mx.collections.ArrayCollection;
  15:              import mx.controls.Image;
  16:              import mx.core.UIComponent;
  17:              import mx.events.FlexEvent;
  18:              import mx.rpc.events.ResultEvent;
  19:              import spark.components.BorderContainer;
  20:              import spark.core.NavigationUnit;
  21:   
  22:              
  23:              [Bindable]
  24:              public var BestFoto:mx.collections.ArrayCollection ;
  25:              public var params:Object;
  26:              
  27:              protected function application1_applicationCompleteHandler(event:FlexEvent):void
  28:              {
  29:                  BestFoto= new mx.collections.ArrayCollection();
  30:                  params = mx.core.FlexGlobals.topLevelApplication.parameters;
  31:                  BestFotoNumber.url=params.BestFotoNumber
  32:                  currentState="Image_Load";
  33:                  try
  34:                  {
  35:                      BestFotoNumber.send();
  36:                  }
  37:                  catch(error:SecurityError)
  38:                  {
  39:                      currentState="Debug";
  40:                      return;
  41:                  }
  42:                  if (params.DebugService=="1"){
  43:                      currentState="Debug";
  44:                  }
  45:              }
  46:              
  47:              private function BestFotoNumberReadEnd(event:mx.rpc.events.ResultEvent):void
  48:              {
  49:                  var i:int;
  50:                  BestFoto = event.result.BestFotoNumbers.BestFoto;
  51:                  for (i=0;i<BestFoto.list.length;i++) {
  52:                      //trace ("BestFoto " + i + " is " + BestFoto[i].j);
  53:                      BestFoto[i].id=params.ClickBaseUrl.toString()+"?i="+BestFoto[i].id+"&j="+BestFoto[i].j;
  54:                      BestFoto[i].j=params.BaseUrl.toString()+BestFoto[i].j;
  55:                  }
  56:                  if (params.DebugService=="1"){
  57:                      DataGrid1.dataProvider = BestFoto;
  58:                  }
  59:                  else{
  60:                      currentState="Image_Load";
  61:                      HGroup1.visible=false;
  62:                                          
  63:                      if (BestFoto.list.length>7){
  64:                          //первые пять видимых добавляем сразу чтобы они были видны, остальные потом
  65:                          AddMyElement(0,5);
  66:                          var BorderContainerTmp:BorderContainer = HGroup1.getElementAt(4) as BorderContainer;
  67:                          var ImageTmp:Image=    BorderContainerTmp.getElementAt(0) as Image;
  68:                          //предполагается что последний выданный реквест все-таки завершится последним 
  69:                          ImageTmp.addEventListener("complete",Image5_completeHandler);
  70:                      }
  71:                      else {
  72:                          AddMyElement(0,BestFoto.list.length);
  73:                          HGroup1.visible=true;
  74:                      }
  75:                  }
  76:              }
  77:              
  78:              protected function Image5_completeHandler(event:Event):void
  79:              {
  80:                  AddMyElement(6,BestFoto.list.length);
  81:                  HGroup1.visible=true;
  82:              }
  83:              
  84:              protected function AddMyElement (From:int, To:int):void {
  85:                  var j:int;
  86:                  for (j=From;j<To;j++) {
  87:                      
  88:                      var NewBorderContainer:BorderContainer = new BorderContainer;
  89:                      NewBorderContainer.width = 115;
  90:                      NewBorderContainer.height = 115;
  91:                      NewBorderContainer.setStyle("backgroundColor", 0xF3EEF4);
  92:                      NewBorderContainer.addEventListener(MouseEvent.ROLL_OVER,NewBorderContainer_MouseOverHandler);
  93:                      NewBorderContainer.addEventListener(MouseEvent.MOUSE_OUT,NewBorderContainer_MouseOutHandler);
  94:                      
  95:                      var NewImage:Image = new Image;
  96:                      NewImage.verticalCenter=5;
  97:                      NewImage.horizontalCenter=0;
  98:                      NewImage.width=100;
  99:                      NewImage.height=100;
 100:                      NewImage.addEventListener(MouseEvent.CLICK,NewImage_clickHandler);
 101:                      NewImage.addEventListener(MouseEvent.ROLL_OVER,NewImage_MouseOverHandler);
 102:                      NewImage.addEventListener(MouseEvent.MOUSE_OUT,NewImage_MouseOutHandler);
 103:                      NewImage.source=BestFoto[j].j;
 104:                      NewImage.data=BestFoto[j].id;
 105:                      NewBorderContainer.addElement(NewImage);
 106:                      
 107:                      HGroup1.addElement(NewBorderContainer);
 108:                  }
 109:              }
 110:              
 111:              protected function scrollToThere(dir:uint):void {
 112:                  var value:Number = HGroup1.getHorizontalScrollPositionDelta(dir);
 113:                  if (value != 0) {
 114:                      pth.valueBy = value;
 115:                      anim.play();
 116:                  }
 117:                  else
 118:                  {
 119:                      if(dir == NavigationUnit.PAGE_RIGHT)
 120:                      {
 121:                          value = HGroup1.getHorizontalScrollPositionDelta(NavigationUnit.HOME);
 122:                          pth.valueBy = value;
 123:                          anim.play();
 124:                      }
 125:                      if(dir == NavigationUnit.PAGE_LEFT)
 126:                      {
 127:                          value = HGroup1.getHorizontalScrollPositionDelta(NavigationUnit.END);
 128:                          pth.valueBy = value;
 129:                          anim.play();
 130:                      }
 131:                  }
 132:              }
 133:   
 134:              protected function NewImage_clickHandler(event:MouseEvent):void
 135:              {
 136:                  var Image1:Image=event.currentTarget as Image;
 137:                  var url:String = Image1.data.toString();
 138:                  var request:flash.net.URLRequest = new URLRequest(url);
 139:                  try {            
 140:                      navigateToURL(request, "_blank");
 141:                  }
 142:                  catch (e:Error) {
 143:                      return;
 144:                  }
 145:              }
 146:   
 147:              protected function NewBorderContainer_MouseOverHandler (e:MouseEvent):void {
 148:                  var Image1:Image=e.currentTarget.getElementAt(0)
 149:                  Image1.buttonMode = true;
 150:                  Image1.useHandCursor = true;
 151:                  Image1.width=110;
 152:                  Image1.height=110;
 153:                  Image1.verticalCenter=5;
 154:                  Image1.horizontalCenter=0;
 155:              }
 156:   
 157:              protected function NewBorderContainer_MouseOutHandler(event:MouseEvent):void
 158:              {
 159:                  var Image1:Image=event.currentTarget.getElementAt(0);
 160:                  Image1.width=100;
 161:                  Image1.height=100;
 162:                  Image1.verticalCenter=5;
 163:                  Image1.horizontalCenter=0;
 164:              }
 165:              
 166:              
 167:              protected function NewImage_MouseOverHandler(event:MouseEvent):void
 168:              {
 169:                  var Image1:Image=event.currentTarget as Image
 170:                  Image1.width=110;
 171:                  Image1.height=110;
 172:                  Image1.verticalCenter=5;
 173:                  Image1.horizontalCenter=0;
 174:              }
 175:              
 176:              protected function NewImage_MouseOutHandler(event:MouseEvent):void
 177:              {
 178:                  var Image1:Image=event.currentTarget  as Image
 179:                  Image1.width=100;
 180:                  Image1.height=100;
 181:                  Image1.verticalCenter=5;
 182:                  Image1.horizontalCenter=0;
 183:              }
 184:          
 185:          ]]>
 186:      </fx:Script>
 187:      
 188:      <s:states>
 189:          <s:State name="Debug"/>
 190:          <s:State name="Image_Load"/>
 191:      </s:states>
 192:      
 193:      <fx:Declarations>    
 194:          <!-- Place non-visual elements (e.g., services, value objects) here -->
 195:          <s:HTTPService id="BestFotoNumber" result="BestFotoNumberReadEnd(event)" />
 196:   
 197:          <s:Animate id="anim" target="{HGroup1}" duration="500">
 198:              <s:motionPaths>
 199:                  <s:SimpleMotionPath id="pth" property="horizontalScrollPosition" />
 200:              </s:motionPaths>
 201:          </s:Animate>
 202:      </fx:Declarations>
 203:      
 204:      <s:layout.Image_Load>
 205:          <s:HorizontalLayout gap="10" verticalAlign="middle"/>
 206:      </s:layout.Image_Load>
 207:   
 208:      <mx:DataGrid id="DataGrid1" width="100%" height="100%" includeIn="Debug" editable="false" x="0" y="0">
 209:          <mx:columns>
 210:              <mx:DataGridColumn dataField="j" headerText="SmallImageURL"/>
 211:              <mx:DataGridColumn dataField="id" headerText="ClickURL"/>
 212:          </mx:columns>
 213:      </mx:DataGrid> 
 214:      
 215:      <s:Button label="&lt;" 
 216:                click="scrollToThere(NavigationUnit.PAGE_LEFT);"
 217:                width="30" includeIn="Image_Load"/>
 218:      
 219:      <s:HGroup id="HGroup1" includeIn="Image_Load" x="52" y="101" width="650" height="125" gap="10" verticalAlign="middle"  variableColumnWidth="false" 
 220:                clipAndEnableScrolling="true" columnWidth="120" >
 221:      </s:HGroup>
 222:      
 223:      <s:Button label="&gt;"
 224:                click="scrollToThere(NavigationUnit.PAGE_RIGHT);"
 225:                width="30" includeIn="Image_Load"/>
 226:   
 227:  </s:Application>

Как видите, код плеера настолько простой, что его даже неловко комментировать. Его даже сравнивать невозможно с крученым кодом ASP.NET. Когда плеер загружается, проверяется режим работы. Если он не debug, то плеер переходит рабочее состояние и дергает webservice (строки 27-45). Когда загрузка первых пяти видимых на фасаде рисунков завершена (строки 47-76), начинается загрузка тех рисунков, которые сразу не видны на фасаде. Так достигается временной лаг для реквестов на сервер, чтобы канал пропустил все, страничка все успела отрисовать, чтобы сервер успел отработать.




В откомпилированном виде весь этот код занимает 50 Килобайт, то есть втрое меньше, чем javascript-библиотека фотосладера. Не говоря уже о том, что это исполняемый байт-код, а не букавки Яваскрипта, которые браузер должен анализировать и превращать в исполняемые команды.

Этот код был бы еще вдвое наверное проще если бы я не вложил в этот свой компонент две фишки - задержку считывания рисунков (которые не видны сразу при загрузке контрола) и режим отладки. Код читает лучшие рисунки сайта, поэтому у него есть режим показа - что именно сайт ему отдает для показа в качестве лучших рисунков сайта - DebugService="1":




Этот параметр DebugService указывается в запускающем скрипте слайдера - в максимальном виде, предлагаемым компанией Adobe (позволяющей догрузить Флеш-плеер на те кампутеры, где нет флеш-плеера) этот враппер выглядит вот так:


   1:          <!-- Enable Browser History by replacing useBrowserHistory tokens with two hyphens -->
   2:          <!-- BEGIN Browser History required section -->
   3:          <link rel="stylesheet" type="text/css" href="history/history.css" />
   4:          <script type="text/javascript" src="history/history.js"></script>
   5:          <!-- END Browser History required section -->  
   6:              
   7:          <script type="text/javascript" src="swfobject.js"></script>
   8:          <script type="text/javascript">
   9:              <!-- For version detection, set to min. required Flash Player version, or 0 (or 0.0.0), for no version detection. --> 
  10:              var swfVersionStr = "10.0.0";
  11:              <!-- To use express install, set to playerProductInstall.swf, otherwise the empty string. -->
  12:              var xiSwfUrlStr = "playerProductInstall.swf";
  13:              var flashvars = {};
  14:              flashvars.BestFotoNumber="http://foto.votpusk.ru/BestFotoNumber.ashx";
  15:              flashvars.DebugService="0";
  16:              flashvars.BaseUrl="http://foto.votpusk.ru/GetImage.ashx?w=100%26j=";
  17:              flashvars.ClickBaseUrl="http://foto.votpusk.ru/foto_slide.aspx";
  18:              var params = {};
  19:              params.quality = "high";
  20:              params.bgcolor = "#ffffff";
  21:              params.allowscriptaccess = "sameDomain";
  22:              params.allowfullscreen = "true";
  23:              var attributes = {};
  24:              attributes.id = "Test1";
  25:              attributes.name = "Test1";
  26:              attributes.align = "middle";
  27:              swfobject.embedSWF(
  28:                  "Test1.swf", "flashContent", 
  29:                  "100%", "100%", 
  30:                  swfVersionStr, xiSwfUrlStr, 
  31:                  flashvars, params, attributes);
  32:              <!-- JavaScript enabled so display the flashContent div in case it is not replaced with a swf object. -->
  33:              swfobject.createCSS("#flashContent", "display:block;text-align:left;");
  34:          </script>
  35:   
  36:   
  37:          <!-- SWFObject's dynamic embed method replaces this alternative HTML content with Flash content when enough 
  38:               JavaScript and Flash plug-in support is available. The div is initially hidden so that it doesn't show
  39:               when JavaScript is disabled.
  40:          -->
  41:          <div id="flashContent">
  42:              <p>
  43:                  To view this page ensure that Adobe Flash Player version 
  44:                  10.0.0 or greater is installed. 
  45:              </p>
  46:              <script type="text/javascript"> 
  47:                  var pageHost = ((document.location.protocol == "https:") ? "https://" :    "http://"); 
  48:                  document.write("<a href='http://www.adobe.com/go/getflashplayer'><img src='" 
  49:                                  + pageHost + "www.adobe.com/images/shared/download_buttons/get_flash_player.gif' alt='Get Adobe Flash player' /></a>" ); 
  50:              </script> 
  51:          </div>
  52:             
  53:             <noscript>
  54:              <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="100%" height="100%" id="Test1">
  55:                  <param name="movie" value="Test1.swf" />
  56:                  <param name="FlashVars" value="BestFotoNumber='http://foto.votpusk.ru/BestFotoNumber.ashx'&DebugService='0'&BaseUrl='http://foto.votpusk.ru/GetImage.ashx?w=100%26j='&ClickBaseUrl='http://foto.votpusk.ru/foto_slide.aspx'" />
  57:                  <param name="quality" value="high" />
  58:                  <param name="bgcolor" value="#ffffff" />
  59:                  <param name="allowScriptAccess" value="sameDomain" />
  60:                  <param name="allowFullScreen" value="true" />
  61:                  <!--[if !IE]>-->
  62:                  <object type="application/x-shockwave-flash" data="Test1.swf" width="100%" height="100%">
  63:                      <param name="quality" value="high" />
  64:                      <param name="bgcolor" value="#ffffff" />
  65:                      <param name="allowScriptAccess" value="sameDomain" />
  66:                      <param name="allowFullScreen" value="true" />
  67:                  <!--<![endif]-->
  68:                  <!--[if gte IE 6]>-->
  69:                      <p> 
  70:                          Either scripts and active content are not permitted to run or Adobe Flash Player version
  71:                          10.0.0 or greater is not installed.
  72:                      </p>
  73:                  <!--<![endif]-->
  74:                      <a href="http://www.adobe.com/go/getflashplayer">
  75:                          <img src="http://www.adobe.com/images/shared/download_buttons/get_flash_player.gif" alt="Get Adobe Flash Player" />
  76:                      </a>
  77:                  <!--[if !IE]>-->
  78:                  </object>
  79:                  <!--<![endif]-->
  80:              </object>
  81:          </noscript>        

Как видите, это скрипт поддерживает браузеры, которые уже ушли в историю и стали экспонатами музея (скрипты из history). Кроме того он грузит скрипт swfobject, который можно разметить вначале странички и который более ли менее гарантирует что в любом современном браузере в теге <div id="flashContent"> окажется вызов флеш-плеера, подобный вызову плеера в строках 54-80 (который написан для описанного выше случая, когда в браузере пользователя не установлена галка разрешения работы Javascript (или просто сайт не находится в доверенной зоне безопасности этого пользователя интернета). Обратите внимание на такую мелочь - параметры во flashvars передаются в urlencode-виде, то есть амперсант передан как %26.

Как вы видите, здесь в параметрах у меня также указано имя сервиса (фактически это просто XML-файл, формируемый сервером), который отдает фото-слайдеру перечень лучших рисунков сайта для показа слайдером.




Как же создать такой XML-файл наиболее простым путем? Его можно было сделать прямо в SQL - как я описал это на страничке Этюды на ASP2. Делаем RSS-канал на одной SQL-процедуре, а можно обойтись и без процедуры и создать XML прямо кодом ASP.NET:


   1:  <%@ WebHandler Language="VB" Class="BestFotoNumber" %>
   2:   
   3:  Imports System
   4:  Imports System.Web
   5:   
   6:  Public Class BestFotoNumber : Implements IHttpHandler
   7:      
   8:      Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
   9:          Try
  10:              Dim CN1 As New Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings("LocalSqlServer").ConnectionString)
  11:              CN1.Open()
  12:              Dim CMD1 As Data.SqlClient.SqlCommand
  13:              CMD1 = New Data.SqlClient.SqlCommand("SELECT TOP 100 dbo.PP8(UserData_i),UserData_ToUser FROM [vOtpusk_].[dbo].[Best_Foto]", CN1)
  14:              context.Response.ContentType = "text/xml"
  15:              context.Response.Write("<?xml version='1.0' encoding='UTF-8'?>")
  16:              context.Response.Write("<BestFotoNumbers>" & vbCrLf)
  17:              Dim DR1 As Data.SqlClient.SqlDataReader = CMD1.ExecuteReader
  18:              While DR1.Read
  19:                  context.Response.Write("<BestFoto>")
  20:                  context.Response.Write("<j>" & DR1(0) & "</j>" & vbCrLf)
  21:                  context.Response.Write("<id>" & DR1(1).ToString & "</id>" & vbCrLf)
  22:                  context.Response.Write("</BestFoto>" & vbCrLf)
  23:              End While
  24:              context.Response.Write("</BestFotoNumbers>" & vbCrLf)
  25:          Catch ex As Exception
  26:              context.Response.ContentType = "text/plain"
  27:              context.Response.Write(ex.Message)
  28:          End Try
  29:   
  30:      End Sub
  31:   
  32:      Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
  33:          Get
  34:              Return False
  35:          End Get
  36:      End Property
  37:   
  38:  End Class

Этот хандлер просто сериализует в XML вот такой рекордсет:




Обратите внимание, что система безопасности флеш-плеера такова, что в корень этого поддомена вотпуска необходимо положить файлик с разрешением - с какого домена флеш-плеерам можно дергать этот XML-файлик http://foto.votpusk.ru/BestFotoNumber.ashx:


   1:  <?xml version="1.0"?>
   2:  <!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
   3:  <cross-domain-policy>
   4:  <allow-access-from domain="*" />
   5:  </cross-domain-policy>

При желании мой код вы можете гнуть в любую сторону. Например в сторону небольшого усложнения - поставить флажки, что реквест всех видимых рисунков на фасаде закончился и только тогда начинать дергать рисунки невидимые. Я предположил, что завершение чтения всех рисунков ожидать не обязательно - достаточно дождаться последнего реквеста на видимый рисунок. Это конечно упрощенный взгляд на вещи. Вот это подпрыгивание тоже можно заменить анимацией, можно фон добавить, ресайз всего компонента, скины какие-нибудь вместо фона. Можно названия рисунков выдернуть с сервера и тоже показать их на слайдере. Можно сделать чтобы рисунки прокручивались сами по себе, по таймеру, а не по кликам. В общем - простора для расширения этого моего OpenSource Flex компонента хоть отбавляй.

В дальнейшем этот проект превратился в серию проектов - своим путем стал развиваться фотослайдер для компании votpusk.ru, появился и стал развиваться своим путем отдельный проект OpenSource фотослайдера.


Надеюсь, чтение этой странички доставило удовольствие заинтересованным лицам из числа web-программистов. Тем, для кого тут оказалось слишком много буков - просьба не беспокоится.

Еще я хотел добавить, что не всегда jQuery выглядит так криво и убого - как в описанном на этой страничке случае. Иногда реальной альтернативы ей просто нет, например такой случай я описал здесь - AJAX подсказка/автозаполнение на jQuery.


Об инструментах для работы c Flex вы можете почитать подробнее на этой страничке - Знакомство с Adobe Flex 4, а на следующей страничке вы можете почитать Как сделать SOAP/WSDL-вебсервис на ASP.NET/MONO для вызова его из FLEX.



Comments ( )
Link to this page: //www.vb-net.com/Flex_Image_Slider/index.htm
< THANKS ME>