Next step after calling a webservice was to visualize the result of a search. To start with Basic, I wanted to get to basic grid (I have few ideas to use by Stack3dPanel in the future but wanted to start with Basics).Some of the functionality explained in this posts are…
I wanted to get to screen shot below.
To get started, I created few helper classes and I will use them later.
I needed to create a class that I can use as a source of Collection. I ended up doing this is because my actual source for databinding is collection of this collection class (2-D array)
Eventually I needed to have to sources for databinding. One was the actual collection itself and I use datacontext to set the source of databinding. Then there are some settings (height/width of each tile or padding around the tile). I created this class so that I can use Source based databinding
Having all this classes, now lets start with a grid view. Here is the XAML that I ended up with…
Here are some of the interesting points about this XAML…
- I did not use Grid panel, instead I used nested ItemsControl. so think of one item control shows a row of images. Then I use another ItemsControl to repeat these rows to get the grid look.
- To achieve this, I set the ItemsPanel property on the inner ItemsControl. I set the panel to be StackPanel (which is default) but I changed the orientation to be Horizontal (Vertical is default). This way I get a row of images
- Outer Items control repeats this inner items control (showing a row of images). This way I get a Grid of Images.
- Since the data context for this control is Collection of collection. Outer Items control sets collection instance in collection of collection to be the source for inner items control.
- Inside inner items control, I have a border that lays out each image (Image element inside).
- Border defines Height/Width/Padding for each tile.
- In the resources section, I have defined a Tile instance.
- Border height/width/margin are databound to TileHeight, TileWidth, TilePadding property of a Tile class.
- Border also defines the interactive behavior through Mouse Enter/leave events.
- Image element is contained within each of the border.
- Image element is bound to Uri returned by search service call
- Since Uri needs to be converted to ImageSource (BitmapImage), I use Value Converters of type ImageSourceConverter
- In the resources section, ImageSourceConverter is added.
- Image element also hooks up the ImageFailed event so that placeholder image can be shown in case, actual image can not be shown.
Now here is the code behind for the control.
This is pretty straight forward too
- Control exposes following public APIs
- TileHeight/TileWidth so that consumer of this control can decide how big the tile should be
- TilePadding because setting height/width to be large has impact on things getting clipped so I also thought consumer should be allowed to set the padding. Padding property is interesting because it actually needs to be bound to Margin which is of type thickness but since I could not parse this property on my custom control, I use a hack. Even though Tile class exposes TilePadding to be of type thickness, I expose it as double. This way, I convert the double to thickness before setting it to Tile that was declared in the resource section and then I can use it in databinding without needing another value converter. Side effect is I assume uniform margin, which I did not think was a big problem for me for this scenario
- These are private members
- ImageFailed event handler, sets the source of the image that failed to place holder image
- Border’s mouse enter event handler, applies a scaletransform to itself so that image looks bigger when mouse is over it, it also sets the opacity to be 1 so that image appears clear
- Border’s mouse leave event handler, resets the scaletransform to 1 so that image goes back to original size and also sets the opacity to be 0.7.
Consumption of Grid Control
New Page.Xaml are above….
- Added a ScrollViewer so that I can get scrollbar if needed, but I have set the scrollbar visibility to Auto so that it does not show up if it is not needed
- Inside Scrollbar, there is ImageGrid control. I have set the TileHeight/Width to be 100.
- I have also added MakeSearchResultVisible storyboard in resources section so that I can fade in the grid view after the search service call is complete.
Here are the few things about the code that might be interesting in order to understand the code…
- I use “_searchresultcollectioncollection” to represent the 2-D array that I need so that I can set it to be source of nested ItemsControl
- I recalculate that everytime search happens or size of the grid changes
- I think, this part could be made lot more tighter but I just stuck with it.
- I also start the animation to fade in the results once query is complete.
Here is the link to working project.