Professional, Software

Part 5: Search Application (Detail View)

The last part of Search Application is the detail view. User comes here when they click on one of the images in the grid. Here is the functionality detail view provides…

  1. ListBox control that has same images as GridView. Individual items in ListBox are of type ImageListBoxItem. I used the sample ListBox control that Silverlight 1.1 Alpha SDK shipped with a small fix.
  2. ImageView control that can show the image in detail view. It also animates the image when user selects another image in listbox by rotating image and swapping it.  It also shows the URI from where Image came from.

User clicks on Grid View and listbox is populated and hooked SelectionChanged events..

void gridviewitem_Click(object sender, GridViewItemClickEventArgs e) 
{ 
    gridview.Items.Clear(); 
    this.Children.Remove(gridview); 
    gridview = null; 
    listbox = new ListBox(); 
    listbox.SelectionChanged += new EventHandler(listbox_SelectionChanged); 
    imageview = new ImageView(); 
    this.Children.Add(listbox); 
    this.Children.Add(imageview); 
    UpdateLayout(); 

    imageview.Source = e.ImageUri; 

    foreach (SearchService.Result r in searchresults) 
    { 
        string imageurl = r.Image.ImageURL.ToLower(); 
        if (imageurl.Contains(".jpg") || imageurl.Contains(".jpeg") || imageurl.Contains(".png")) 
            AddItemToList(r); 
    } 

    listbox.UpdateItems(); 

} 

void AddItemToList(SearchService.Result result) 
{ 
    ImageListBoxItem imagelistitem = new ImageListBoxItem(); 
    imagelistitem.Height = itemheight; 
    imagelistitem.Width = itemwidth; 
    imagelistitem.Source = new Uri(result.Image.ImageURL); 
    if (imagelistitem.ValidImage == true) 
        listbox.Items.Add(imagelistitem); 
} 

void listbox_SelectionChanged(object sender, EventArgs e) 
{ 
    ImageListBoxItem selecteditem = (ImageListBoxItem)listbox.SelectedItem; 
    imageview.Source = selecteditem.Source; 
    imageview.Description = selecteditem.Source.ToString(); 
}

Source code for ImageListBoxItem.xaml

<Canvas xmlns="http://schemas.microsoft.com/client/2007" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        Width="100" 
        Height="100" 
        x:Name="rootCanvas" Background="#FF080808" 
        > 
    <Image x:Name="imageThumbnail" Width="84" Height="84" Canvas.Left="8" Canvas.Top="8"/> 
    <Rectangle Stroke="#FF757575" StrokeThickness="3" x:Name="rectborder" Width="100" Height="100"/> 
</Canvas>

Source code for ImageListBoxItem.xaml.cs

using System; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Documents; 
using System.Windows.Ink; 
using System.Windows.Input; 
using System.Windows.Media; 
using System.Windows.Media.Animation; 
using System.Windows.Shapes; 

namespace SearchApplication 
{ 
    public class ImageListBoxItem : Control 
    { 
        /// <summary> 
        /// Private Variables 
        /// </summary> 
        private Canvas rootCanvas; 
        private Image imageThumbnail; 
        private bool _validImage = true; 
        private SolidColorBrush _originalBackground; 
        private Rectangle rectBorder; 

        public ImageListBoxItem() 
        { 
            System.IO.Stream s = this.GetType().Assembly.GetManifestResourceStream("SearchApplication.ImageListBoxItem.xaml"); 
            rootCanvas = (Canvas) this.InitializeFromXaml(new System.IO.StreamReader(s).ReadToEnd()); 
            imageThumbnail = (Image) rootCanvas.FindName("imageThumbnail"); 
            rectBorder = (Rectangle)rootCanvas.FindName("rectborder"); 
            this.Loaded += new EventHandler(ImageListBoxItem_Loaded); 
            imageThumbnail.ImageFailed += new ErrorEventHandler(imageThumbnail_ImageFailed); 
            _originalBackground = rootCanvas.Background as SolidColorBrush; 
            rootCanvas.MouseEnter += new MouseEventHandler(rootCanvas_MouseEnter); 
            rootCanvas.MouseLeave += new EventHandler(ImageListBoxItem_MouseLeave); 
        } 

        void ImageListBoxItem_MouseLeave(object sender, EventArgs e) 
        { 
            rootCanvas.Background = _originalBackground; 
            this.Height = 100; 
            this.Width = 100; 
        } 

        void rootCanvas_MouseEnter(object sender, MouseEventArgs e) 
        { 
            rootCanvas.Background = new SolidColorBrush(Colors.Gray); 
            this.Height = 110; 
            this.Width = 110; 
        } 

        void imageThumbnail_ImageFailed(object sender, ErrorEventArgs e) 
        { 
            _validImage = false; 
        } 

        ///Source Property 
        public Uri Source 
        { 
            get { return imageThumbnail.Source; } 
            set 
            { 
                imageThumbnail.Source = value; 
                UpdateLayout(); 
            } 
        } 

        public bool ValidImage 
        { 
            get { return _validImage; } 
        } 

        /// <summary> 
        /// General Layout Functionality 
        /// </summary> 

        void ImageListBoxItem_Loaded(object sender, EventArgs e) 
        { 
            UpdateLayout(); 
        } 

        public new double Height 
        { 
            get { return ((FrameworkElement)this).Height; } 
            set 
            { 
                ((FrameworkElement)this).Height = value; 
                UpdateLayout(); 
            } 
        } 

        public new double Width 
        { 
            get { return ((FrameworkElement)this).Width; } 
            set 
            { 
                ((FrameworkElement)this).Width = value; 
                UpdateLayout(); 
            } 
        } 

        private void UpdateLayout() 
        { 
            rootCanvas.Height = Height; 
            rootCanvas.Width = Width; 
            imageThumbnail.Height = Height - 16; 
            imageThumbnail.Width = Width - 16; 
            rectBorder.Height = Height; 
            rectBorder.Width = Width; 

        } 
    } 
} 

Source code for ImageView.xaml

<Canvas xmlns="http://schemas.microsoft.com/client/2007" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        Width="600" 
        Height="700" 
        x:Name="rootCanvas" 
        Background="Black" 
        > 
  <Canvas.Resources> 
    <Storyboard x:Name="flip"> 
      <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="imageDetail" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)"> 
        <SplineDoubleKeyFrame KeyTime="00:00:00" Value="1"/> 
        <SplineDoubleKeyFrame KeyTime="00:00:00.2500000" Value="0"/> 
        <SplineDoubleKeyFrame KeyTime="00:00:00.5000000" Value="1"/> 
      </DoubleAnimationUsingKeyFrames> 
    </Storyboard> 
    <Storyboard x:Name="fakeFlip"> 
      <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="txtDetail" Storyboard.TargetProperty="(UIElement.Opacity)"> 
        <SplineDoubleKeyFrame KeyTime="00:00:00.2500000" Value="0"/> 
      </DoubleAnimationUsingKeyFrames> 
    </Storyboard> 
  </Canvas.Resources> 
  <Image x:Name="imageDetail" Width="600" Height="600" Canvas.Left="0" Canvas.Top="0" RenderTransformOrigin="0.5,0.5" Stretch="Uniform" > 
    <Image.RenderTransform> 
      <TransformGroup> 
        <ScaleTransform ScaleX="1" ScaleY="1"/> 
      </TransformGroup> 
    </Image.RenderTransform> 
  </Image> 
  <TextBlock x:Name="txtDetail" Width="600" Height="100" Canvas.Left="0" Canvas.Top="600" TextWrapping="Wrap" Foreground="#FFFFEEEE"/> 
</Canvas>

Source code for ImageView.xaml.cs

using System; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Documents; 
using System.Windows.Ink; 
using System.Windows.Input; 
using System.Windows.Media; 
using System.Windows.Media.Animation; 
using System.Windows.Shapes; 

namespace SearchApplication 
{ 
    public class ImageView : Control 
    { 
        private Canvas rootCanvas; 
        private TextBlock txtDetail; 
        private Image imageDetail; 
        private Storyboard flip; 
        private Storyboard fakeFlip; 
        private Uri _source; 

        public ImageView() 
        { 
            System.IO.Stream s = this.GetType().Assembly.GetManifestResourceStream("SearchApplication.ImageView.xaml"); 
            rootCanvas = (Canvas) this.InitializeFromXaml(new System.IO.StreamReader(s).ReadToEnd()); 
            txtDetail = (TextBlock)rootCanvas.FindName("txtDetail"); 
            imageDetail = (Image)rootCanvas.FindName("imageDetail"); 
            flip = (Storyboard)rootCanvas.FindName("flip"); 
            fakeFlip = (Storyboard)rootCanvas.FindName("fakeFlip"); 
            fakeFlip.Completed += new EventHandler(fakeFlip_Completed); 
            flip.Completed += new EventHandler(flip_Completed); 
            this.Loaded += new EventHandler(ImageView_Loaded); 
            imageDetail.ImageFailed += new ErrorEventHandler(imageDetail_ImageFailed); 
        } 

        void imageDetail_ImageFailed(object sender, ErrorEventArgs e) 
        { 
            this.imageDetail.Source = null; 
        } 

        void flip_Completed(object sender, EventArgs e) 
        { 
            fakeFlip.Stop(); 
            flip.Stop(); 
            txtDetail.Opacity = 1; 
        } 

        void fakeFlip_Completed(object sender, EventArgs e) 
        { 
            imageDetail.Source = _source; 
        } 

        public Uri Source 
        { 
            get { return imageDetail.Source; } 
            set 
            { 
                flip.Begin(); 
                fakeFlip.Begin(); 
                _source = value; 
            } 
        } 

        public string Description 
        { 
            get { return txtDetail.Text; } 
            set { txtDetail.Text = value; } 
        } 

        /// <summary> 
        /// Typical Layout methods 
        /// </summary> 
 
        void ImageView_Loaded(object sender, EventArgs e) 
        { 
            UpdateLayout(); 
        } 

        public new double Height 
        { 
            get { return ((FrameworkElement)this).Height; } 
            set 
            { 
                ((FrameworkElement)this).Height = value; 
                UpdateLayout(); 
            } 
        } 

        public new double Width 
        { 
            get { return ((FrameworkElement)this).Width; } 
            set 
            { 
                ((FrameworkElement)this).Width = value; 
                UpdateLayout(); 
            } 
        } 

        private void UpdateLayout() 
        { 
            rootCanvas.Height = Height; 
            rootCanvas.Width = Width; 
            txtDetail.Width = Width; 
            imageDetail.Width = Width; 
            txtDetail.Height = Height / 7; 
            imageDetail.Height = txtDetail.Height * 6; 
        } 

    } 
} 

Standard

18 thoughts on “Part 5: Search Application (Detail View)

  1. Pingback: Recursive Reflection : Part 5: Search Application (Detail View)

  2. Does anyone have a working sample of this code they could send me? I’m just starting to learn Silverlight and seeing a working program would be very helpful. Send to rbunn83815 [at] yahoo.com. Thank you.

  3. I will post the full sample. Since it contains a webservice, i need to figure out how to make it transferrable and somebody can download it and still just run it.

  4. Maybe this wasn’t as straightforward as I thought initially. Do you think you could summarize the steps necessary to get this running? I’ve never used a web service before and apparently I’m missing something here in the setup. I put in the appid and that seemed to work all right. Also I’m getting an error message saying the application does not know where to find liveimages.css?v=2_3_1_40482&rev=2.
    Also, I have a number of sites I can run this webservice from just not sure how to get it started. Also, will I need to change the bombayboy url to something else when I am setting this up? I hate to ask so many questions, but this is a first rate sample using both web services and Silverlight which I really want to learn from. Thanks for your help.

  5. I had put steps in
    https://vivekdalvi.wordpress.com/2007/05/22/part-2-search-application-live-web-service/

    1) I created an asmx web service called “LiveWebService”.
    2) Got an APP ID following instructions here.
    3 ) Added a web reference to http://soap.search.msn.com/webservices.asmx?wsdl where actual web service lives. I named the reference LiveSearch.

    Does this help? Once you do this your web service should be running and you can even test it without the application.

    yes you will need to change bombayboy URL to your website url. your website also needs to have ASP.net.

    Thanks for the compliment. I will definitely help you getting this sample running on your machine so let me know if this helps or not

  6. Okay, so if I understand this correctly I need to upload the files in the folder “website1” to a hosting site. Then I change the bombayboy url to the url of wherever I uploaded “website1”. I hope these aren’t dumb questions, but for the life of me I can’t find a web services tutorial that explains how they work to a total newbie. They always assume you already know this or that to shorten the length of their tutorial I guess. If anyone has a good suggestion for a web services tutorial for newbies please include it in the comments as I’m sure I’m not the only one trying to figure all this stuff out. Thanks again for your help.

  7. I found some information that explains some of the things that were tripping me up here. Pasted below:

    This web service is using http://tempuri.org/ as its default namespace.
    Recommendation: Change the default namespace before the XML Web service is made public.
    Each XML Web service needs a unique namespace in order for client applications to distinguish it from other services on the Web. http://tempuri.org/ is available for XML Web services that are under development, but published XML Web services should use a more permanent namespace.

    Your XML Web service should be identified by a namespace that you control. For example, you can use your company’s Internet domain name as part of the namespace. Although many XML Web service namespaces look like URLs, they need not point to actual resources on the Web. (XML Web service namespaces are URIs.)

    For XML Web services creating using ASP.NET, the default namespace can be changed using the WebService attribute’s Namespace property. The WebService attribute is an attribute applied to the class that contains the XML Web service methods.

  8. Peter says:

    I have downloaded your source package as well and am having some difficulty in getting it to run.

    If I comment out the line in public void Search: livecall.BeginSearchImages(searchstring, this.SearchCompleted, livecall); The application runs but it stops with the progress gui cycling.

    If I do not comment out that line, I get a very long error message in a popup: (short version) ErrorCode: 1001 Cross Domain calls are not supported by BrowserHttpWebRequest

    This leads me to think the issue is with the webservice; however, if I call localhost/test/livewebsearch.asmx?op=SearchImages the code returns a LiveWebSearch page.

    I have setup my APPID. I do not know what I am missing.

  9. Okay, it runs great now! The only thing I found found so far is the program can’t seem to find the following:
    liveimages.css?v=2_3_1_40482&rev=2
    What is it, do I need it, or can I just delete the reference to it all together? By the way, this is a truly incredible sample. Also, you can’t seem to click on any image to go to the web site where it is located. Is this something you are still working on, or should it be working now?

  10. Peter says:

    I am still getting the same error when I enter in the search request. I must have done something wrong with the webservice.

    I downloaded the latest zip. I edited the url to match my iis virtual directory (setup for .net 2.0). I changed my APPID. I run http://localhost/test1/testpage.html

    The search page shows. I enter the search query and hit enter. I get the “does not support cross domain” error message.

    Is there a way I can better test to verify I have the webservice setup and working correctly?

  11. yeah i had the same problem. I am not sure if this is a bug in VS where publishing is not completely working. The work around for now is you have to remove the web service reference that i have in my search application and explicitly point to your service on the localhost. It worked for me

  12. Peter,
    There are 2 test pages in the zip. Use the one that doesn’t automatically put in a search term for you (which is James Bond in this sample).

  13. I am trying to put a Default.aspx page in the root directory so this page will load and search when put on a server. I cannot seem to figure out how to put the start page in the root directory and still have it run correctly. I also would like to say I am learning a lot about both web services and silverlight from this example, but I’m just stuck on this problem for some reason.

Leave a reply to Robert Cancel reply