locked
Extension: Random Image control RRS feed

  • Question

  • User742541801 posted

    I wanted to add a control that would randomly select an image from the library, and display it in a leftblock on any particular ASPX page in the site. So I created a new custom control. When it loads, it selects a random image. It then generates an image tag in the HTML, with the appropriate image data. The control then wraps a hyperlink around the image; when clicked the link opens up the album that contains the image in question, using the existing PhotoAlbum_Contents.aspx.

    This is the new control, put it into a new file called ImageRandom.ascx:

    <%@ Control Language="C#" ClassName="ImageRandom" %>
    <script runat="server">
        public int MaxWidth
        {
            get
            {
                object o = ViewState["MaxWidth"];
                return (o != null) ? Convert.ToInt32(o.ToString()) : 0;
            }
            set
            {
                ViewState["MaxWidth"] = value;
            }
        }
    
        private int imageId = 0;
    
        protected void Page_PreRender(object sender, System.EventArgs e)
        {
            int[] x= ImageUtils.SelectRandomPhoto();
            Image1.ImageUrl = "ImageFetch.ashx?Size=" + MaxWidth.ToString() + "&ImageID=" + x[0].ToString();
            Hyperlink1.NavigateUrl = "PhotoAlbum_Contents.aspx?AlbumId=" + x[1].ToString() + "&ImageID=" + x[0].ToString();
        }
    </script>
    
    
    <asp:HyperLink ID="Hyperlink1" runat="server">
    	<asp:Image ID="Image1" runat="server" CssClass="picture" BorderWidth="1" />
    </asp:HyperLink> 
    
    

    To use the control, stuff something like this into an ASPX page:

    <%@ Register TagPrefix="Club" TagName="ImageRandom" Src="ImageRandom.ascx" %>
    ...
    <asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="Server">
        <div id="body">
            <!--Start of left column-->
            <div id="columnleft">
            ...
                <div class="leftblock">
                    <h3>
                        Photo pick:</h3>
                    <Club:ImageRandom ID="ImageRandom" runat="server" MaxWidth="180" />
                </div>
            ...
            </div>
         ...
    
    

    The control references a new static method in the ImageUtils class - so add this to App_Code\ImageHandling.cs :

        public static int[] SelectRandomPhoto()
        {
            SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["ClubSiteDB"].ConnectionString);
            
            // randomly select an image
            SqlCommand command = new SqlCommand("select MAX(id) from images", connection);
            connection.Open();
            int maxId = (int)command.ExecuteScalar();
    
            // now, select an imageID randomly, and verify that it is attached to an album (any album)
            System.Random rnd = new System.Random();
            command = new SqlCommand("select album from images where id=@id", connection);
            SqlParameter p0 = new SqlParameter("@id", SqlDbType.Int);
            command.Parameters.Add(p0);
            int ImageID=0, albumId = 0;
            do
            {
                ImageID = rnd.Next(1, maxId+1);
                p0.Value = ImageID;
                albumId = (int)command.ExecuteScalar();
            } while (albumId == 0);
            connection.Close();
    
            return new int[] {ImageID, albumId};
        }
    

    Finally, the PhotoAlbum_Contents.aspx page - if you want to open an album to a particular image, you need to add an OnIteBound event handler to the DataList2, like so:

                    <asp:DataList ID="DataList2" runat="server" DataSourceID="SqlDataSource2" DataKeyField="id"
                        RepeatColumns="2" CellSpacing="2" 
                        OnItemDataBound="ItemBound"
                        ...
    

    And then this is the ItemBound method, which should also go into that page (Photoalbum_Contents.aspx). What it does is sets the particular photo to "selected" in the list, when that is the "requested" image in the querystring.

        private int _requestedImageId=-455;
        private int RequestedImageId
        {
            get
            {
                if (_requestedImageId == -455)
                {
                    object o = Request.QueryString["ImageID"];
                    if (o != null)
                        _requestedImageId = System.Convert.ToInt32(o);
                    
                }
                return _requestedImageId;
            }
        }
    
       protected void ItemBound(Object sender, DataListItemEventArgs e)
        {
            if (e.Item.GetType().Name == "DataListItem")
            {
                DataListItem item = (DataListItem)e.Item;
                System.Data.DataRowView drv = (System.Data.DataRowView)item.DataItem;
                if ((int)drv[0] == RequestedImageId)
                {
                    DataList2.SelectedIndex = item.ItemIndex;
                    item.ControlStyle.CssClass = "selected";
                    Trace.Write(String.Format("item {0} selected, ID={1}", item.ItemIndex, RequestedImageId));
                    DataList2_SelectedIndexChanged(null, null);
                }
                else
                {
                    Trace.Write(String.Format("item {0} NOT selected, ID={1}", item.ItemIndex, RequestedImageId));
                }
            }
        }
    
    
    Monday, April 17, 2006 12:38 PM

All replies

  • User654902800 posted

    Very cool cheeso!

    Your SelectRandomPhoto() hits the DB at least twice and maybe more if you have deleted images. May I suggest you let the DB do the work of picking a random row? You can do this with NEWID():

        public static int[] SelectRandomPhoto()
        {
            SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["ClubSiteDB"].ConnectionString);
           
            // randomly select an image
            SqlCommand command = new SqlCommand("SELECT TOP 1 id, album FROM images ORDER BY NEWID()", connection);
            connection.Open();
            SqlDataReader myReader = command.ExecuteReader();
            int ImageID = myReader.GetInt32(0);
            int albumId = myReader.GetInt32(1);
            myReader.Close();
            connection.Close();

            return new int[] {ImageID, albumId};
        }

    Or something like that.

    Cheers,

    Tuesday, April 18, 2006 3:47 PM
  • User742541801 posted

    Hey MrLunch,

    nice, I like optimizations.  I knew my implementation was a lazy way to do it, but I am no T-SQLer.  What does NEWID() do, and what does the query do?  (can you translate in english?)

    -Cheeso  

     

    Tuesday, April 18, 2006 5:41 PM
  • User742541801 posted

    MrLunch, after reading up on it a bit, now I understand newid().  Great suggestion, thanks!   It does exactly what I want, but more efficiently.  I added in a myReader.Read() and a WHERE clause.  Here's the actual code I used: 

        public static int[] SelectRandomPhoto()

        {

            SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["ClubSiteDB"].ConnectionString);

     

            // randomly select an image (it must be associated to an album)

            SqlCommand command = new SqlCommand("SELECT TOP 1 id, album FROM images WHERE album<>0 ORDER BY NEWID()", connection);

            connection.Open();

            SqlDataReader myReader = command.ExecuteReader();

            myReader.Read();

            int ImageID = myReader.GetInt32(0);

            int albumId = myReader.GetInt32(1);

            myReader.Close();

            connection.Close();

     

            return new int[] { ImageID, albumId };

        }

     

    Tuesday, April 18, 2006 6:21 PM
  • User654902800 posted

    Oops! Yeah, gotta do .Read() to get anywhere :)

    > I knew my implementation was a lazy way to do it

    Nah, lazy is where you write *less* code ;-)

    Cool controls man, keep it up!

    Cheers

    Tuesday, April 18, 2006 7:20 PM