How to use Silverlight Toolkit themes

by Naveen 14. July 2010 13:51

When you are working on a rich user interface application, the most important thing that you need to figure out is how you can make your user interface appealing and intutive. As developer you can put together the back end plumbing to fetch the data and wire it to the user interface. But its the design part that can be tricky at times. You try to figure out color schemes and layout details of your pages and controls to make it appealing to your users.

Silverlight Toolkit provides more than a dozen themes that you can choose to implment your user interface look and feel. Some time you find that one theme may not fit all the needs. Well, tool kit does not stop you from mixing the themes as well. In this post I will show simple steps on how to use Themes from Silverlight Toolkit.

Install Silverlight Toolkit

If you are reading this post then there is good chance that you already know what silverlight toolkit is and you have already installed it. But for sake of completion, I will provide the link from where you can download latest toolkit.

Download Silverlight Toolkit From CodePlex

Add Assembly Reference

Add reference to theme assemblies as per your need. Each theme is contained in with in its own assembly. You can add reference to all or what you need. For example I wanted to add Shiny Red and Rain Purple themes to my project. So I have added reference to those assemblies only. Following screen shot how the references look like in my project.

Add Theme From Toolbox

Adding a theme to your page is as simple as dropping a control from the toolbox. If you look under Silverlight Controls node in Toolbox, you will find the controls as shown in the snapshot below. Pick the one that you want to use and drop in on your Silverlight page surface. You will see a code snippet as shown below appear on your page's XAML.


<shinyRedTheme:ShinyRedTheme>
 <Grid x:Name="LayoutRoot">
  <ScrollViewer x:Name="PageScrollViewer" Style="{StaticResource PageScrollViewerStyle}">
   <StackPanel x:Name="ContentStackPanel">
    <toolkit:RainierPurpleTheme Height="50" Name="rainierPurpleTheme1" Width="100">
     <Button x:Name="ClickItButton" Content="Click Me!" Width="Auto"></Button>
    </toolkit:RainierPurpleTheme>
   </StackPanel>
  </ScrollViewer>
 </Grid>
</shinyRedTheme:ShinyRedTheme>

The tag prefix toolkit and shinyRedTheme are ones that need to be defined at top of your page with other namespace declaration. When you drop a theme from toolbox on the page, the declaration gets added at top of the page automatically. Here is what it looks like in my project.


xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit"

shinyRedTheme is namespace declaration that I added manually.

Add Controls

One you have dropped a theme on the page, you can add your UI controls inside that theme's container and all the controls with in that block will have that theme applied to it.

Mix Themes On Silverlight Page

If your UI needs to more than one themes and needs to be nested, there is nothing special you will need to do. Simple drag and drop another theme inside one theme and you are good to go. Following image shows rainier purple theme nested inside shiny red theme. And the XAML code snippet above reflects it as well.

I hope this gives you a good starting point on how to use themes from silverlight toolkit.

 

Views: 3292

Tags:

Silverlight

Break point not hitting in Silverlight - Enable Silverlight Debugging in ASP.Net Project

by Naveen 13. July 2010 13:25

Recently when I was debugging one of my Silverlight projects, I was not hitting break points inside my Silverlight code. Debugging has been working fine on that project. My initial reaction was that my recent changes to the control probably did not update XAP file in my ASP.Net project and I was trying to debug against old executable. I tried to manually take care of that part but I was still not hitting break point. ThenI realized that I had upgraded my project from VS2008 to VS2010. So I took a look at properties of my web project. It turned out that Silverlight debugging code disabled in the project. I turned in on and everything was perfectly fine after that and was hitting all break points inside Silverlight code. Following snapshot shows the setting in Project Properties > Web tab.

 

Views: 4941

Tags: ,

Silverlight | Silverlight

The non-generic method 'Microsoft.Practices.Unity.IUnityContainer.Resolve cannot be used with type arguments

by Naveen 30. June 2010 18:08

I was working on introducing Unity Framework for Silverlight in one of my older Silverlight applications. I was trying to use Resolve to get hold of singleton instance of one of my objects. I kept getting following compile time error.

error CS0308: The non-generic method 'Microsoft.Practices.Unity.IUnityContainer.Resolve(System.Type, string, params Microsoft.Practices.Unity.ResolverOverride[])' cannot be used with type arguments

There was nothing wrong with the code that I had to call Resolve method. After doing dance for more than an hour with everything I could try, I finally figured out the problem and kicked myself. I never added using declaration for Unity namespace in the class where I was using the code. After adding following line, everything was normal in my world.

using Microsoft.Practices.Unity;
 

Views: 4487

Tags:

.Net | C# | Silverlight

Silverlight Grid Layout and Star Sizing

by Naveen 27. April 2010 04:35

When you are building an User Interface, the biggest challenge you face is how to layout your controls to present the data in the best possible way to the user. Yes, style and skins are important too but at the end it all depends on how you layout the controls. And root of all the layout is some container that you use. In Silverlight you have choice of using one of the following containers to create a layout for your application or control.

  • Canvas
  • Grid
  • StackPanel

Unless you are developing some application that requires precise placement of controls based on exact position coordinates and things like that, most of us end up with Grid as container for all other controls. Therefore it is important that you understand how Grid layout works.

See an example

Following XAML snippet and picture shows layout of example that I created.


<Grid x:Name="LayoutRoot" Background="{StaticResource app_background}" 
	ShowGridLines="True">
 <Grid.RowDefinitions>
  <RowDefinition Height="40"></RowDefinition>
  <RowDefinition Height="*"></RowDefinition>
  <RowDefinition Height="2*"></RowDefinition>
  <RowDefinition Height="20"></RowDefinition>
 </Grid.RowDefinitions>
 <Grid.ColumnDefinitions>
  <ColumnDefinition Width="Auto"></ColumnDefinition>
  <ColumnDefinition Width="*"></ColumnDefinition>
  <ColumnDefinition Width="3*"></ColumnDefinition>
 </Grid.ColumnDefinitions>
 <Button Content="Communicate" Height="23" HorizontalAlignment="Left" 
  Margin="0" Name="button1" VerticalAlignment="Top" Width="Auto" 
  Click="OnCommunicate" />
</Grid>

silverlight grid layout

The intention of this layout is to create a grid with 4 rows and 3 columns. I will explain other concepts about layout in the rest of the post.

Defining Rows and Columns

Grid layout is like any other grids. It has rows and columns. Use of RowDefinitions and ColumnDefinitions tags provide you a way to specify how many rows and columns you want in the grid and how you would like to size them. You do not have to specify these explicitly. If you do not specify these dimensions, the framework will automaticall insert the controls into Column 0 and row 0 for you. And it will size the content in these columns based on Auto size.

Specify Height and Width

As you can see in the XAML code above, I have specified height of rows using Height property and width using Width property on rows and column definition. You can there are different ways to specify these dimensions.

  • Auto: What this option means is that you want Silverlight framework to extend height or width dimension to fit the content. In the example above, you can see that I added a button to Row=0,Column=0. I specified fixed height of 40 for first row but I have set width of first column to Auto. This allows my first column to be as wide as it need to fit the button. If you do not set these dimension properties to any value, then Auto is default value that these take.
  • * or Star: This option is also called Star Sizing. This value is something that some people get confused with. This is more like specifying a dimension in "%" terms but more advanced. What this * means is that it wants Silverlight framework to allocate remaining space in proportion to number of STARS. Remaining is key to this option. This remaining is the space left after layout has accomodated FIXED and AUTO dimensions.

    Lets look at the example above for RowDefinitions. I have specified first row to be fixed height of 40, fourth row as fixed height of 20. Then second row as * and third row as 2*. Lets assume that total height of our grid is 400. So what this means is:

    • Row 0: 40 px
    • Row 3: 20 px

    Now we have (400 - 60)=340px left. This remaining height is to be divided between Row 1 and Row 2 as per Start Sizing set. We have 1 * for Row 1 and 2 * for Row 2. These values means is of the remaing 340 px left to be allocated, give 1/3 to Row 1 and 2/3 to Row 2. So as per this at the end we have:

    • Row 0: 40 px
    • Row 1: (340/3)= 113 px
    • Row 2: (340*2/3)= 226 px
    • Row 3: 20 px

Based on this information, you should be able to figure out how sizing will work for width in columns. You can see flexible and convenient is to use Star Sizing. It provides a lot of control on how to dynamically size layouts proportionally. B

 

Views: 9206

Tags: ,

Silverlight

Silverlight WCF Error - Custom tool warning: The type 'System.Collections.ObjectModel.ObservableCollection`1' could not be found

by Naveen 16. April 2010 04:59

While developing a Silverlight applicatio, I ran into the following error when I tried to add service reference to one of my WCF services.

Custom tool warning: The type 'System.Collections.ObjectModel.ObservableCollection`1' could not be found

This was really strange because I had the reference to this WCF earlier and I was not running into any issues. I made some service contract interface changes so I had to update the reference in my silverlight application as well. For a moment I thought that the new DataContract and DataMember that I added into the service contract may have something to do with it. I had added a new property to my DataContract which was an enumeration. So I removed that from the contract. I still kept getting the same error.

After fighting with it for an hour or so, I decided to use the ultimate solution that I happen to use for most Microsoft products. I closed the solution and shut down instance of Visual Studio. And then restarted Visual Studio and loaded my projects. Now I added Service Reference to same WCF service and no errors. It seems that there is some bug or something in Visual Studio's reference generation tool that triggers when there is significant change in your service's contracts.

Bottom line is that if you run into similar errors with WCF Service Reference tool, first try this wonderful solution of restarting Visual Studio and reloading your project.

 

Views: 5958

Tags: ,

Silverlight | WCF

Error adding reference to assembly downloaded from internet

by Naveen 17. March 2010 12:03

If you download a .Net assembly from internet and then add reference to it in your .Net project, you will run into the following compile time error. This happens when you do it in VS2010 and using .Net 4.0 framework. The reason behind this is described in description of <loadFromRemoteSources> in MSDN documentation.


The "ValidateXaml" task failed unexpectedly.
System.IO.FileLoadException: Could not load file or assembly 'file:///C:\Projects\xyz.dll'
or one of its dependencies. Operation is not supported. (Exception from HRESULT: 0x80131515
File name: 'file:///C:\Projects\xyz.dll' ---> System.NotSupportedException: An attempt was
made to load an assembly from a network location which would have caused the assembly to be
sandboxed in previous versions of the .NET Framework. This release of the .NET Framework
does not enable CAS policy by default, so this load may be dangerous. If this load is not
intended to sandbox the assembly, please enable the loadFromRemoteSources switch.
See http://go.microsoft.com/fwlink/?LinkId=155569 
for more information.
   at System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName,
 String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, 
StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection,
Boolean suppressSecurityChecks)
   at System.Reflection.RuntimeAssembly.nLoad(AssemblyName fileName, String codeBase, 
Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, 
 Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
   at System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef, 
Evidence assemblySecurity, StackCrawlMark& stackMark, 
Boolean forIntrospection, Boolean suppressSecurityChecks)
   at System.Reflection.RuntimeAssembly.InternalLoadFrom(String assemblyFile, 
Evidence securityEvidence, Byte[] hashValue, AssemblyHashAlgorithm hashAlgorithm, 
Boolean forIntrospection, Boolean suppressSecurityChecks, StackCrawlMark& stackMark)
   at System.Reflection.Assembly.LoadFrom(String assemblyFile)
   at Microsoft.Silverlight.Build.Tasks.ValidateXaml.XamlValidator.Execute(ITask task)
   at Microsoft.Silverlight.Build.Tasks.ValidateXaml.XamlValidator.Execute(ITask task)
   at Microsoft.Silverlight.Build.Tasks.ValidateXaml.Execute()
   at Microsoft.Build.BackEnd.TaskExecutionHost.Microsoft.Build.BackEnd.ITaskExecutionHost.
Execute()

Solution

Just right click on that assembly and click on Unblock button in bottom right of the dialog box. That should take care of this error.

 

Views: 5050

Tags:

.Net | Silverlight

Silverlight Error - Invalid or malformed application: Check manifest

by Naveen 17. March 2010 05:18

I was working on development of a Silverlight control. The development was mostly converting an existing application to use new SL framework. When I tried to debug the application, I got hard exception thrown at me.

Invalid or malformed application: Check manifest

So I decided to look at AppManifest.xaml file that gets packed in XAP package. The way to do that is as follows:

  • In ClientBin folder of web application rename your .xap file to .zip file
  • Open this renamed ZIP file to extract the contents. There you will find your AppManifest.xaml file
  • Open this AppManifest.xaml file in editor to examine the entries. This will contain what all is going to be packaged for your Silverlight application

I was not expecting anything wrong with this manifest file or the contents of the package itself. After some digging around I realized that I had changed default namespace of Silverlight application project and changed namespaces of all classes to match that as well. But I never changed the entry point of the application in project settings. So I brought up the properties dialog box for the project and fixed the Startup Object value and everything went to normal.

 

Views: 9454

Tags:

Silverlight

How to use HttpWebRequest to send POST request to another web server in Silverlight?

by Naveen 10. March 2010 10:14

Download Sample Projects (114.64 kb)

Quite some time back I wrote about How to use HttpWebRequest to send POST request to another web server in ASP.Net applications. Now that a lot of silverlight applications are being developed, we have similar need to post data from silverlight applications. The concept is exactly the same that I used in ASP.Net. But there is little difference. Silverlight does not allow blocking synchronous requests. All web requests are asynchronous. That means we have little bit more book keeping to do and manage the thread contexts etc. to make sure that then requests complete and we need to do any UI work in call back methods, we stay in correct thread context.

To keep example simple, I am going to post two values to destination URL using POST method. In the attached project, on Slots.xaml page, I have added a simple button Submit Data. And in the event handler of this button, I initiated request to submit data to Default page of sample web application. The event handler for the click looks as below.


private void SubmitData_Click(object sender, RoutedEventArgs e)
{
 // Prepare web request...
 HttpWebRequest myRequest =
 (HttpWebRequest)WebRequest.Create("http://localhost/SilverGridWeb/Default.aspx");
 myRequest.Method = "POST";
 myRequest.ContentType = "application/x-www-form-urlencoded";
 myRequest.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), myRequest);
}

This code is pretty much same as what I had in ASP.Net application. There is one difference. Instead of calling GetRequestStream method, you will need to call BeginGetRequestStream. This will initiate an asynchronous request. There are two parameters that are passed to this method. First is the callback method that needs to be called when this method completes. Second parameter is any object that you want to pass to callback method. So here I have passed my HttpWebRequest object itself.

Now lets look at what is this callback method GetRequestStreamCallback. I copied the function from Microsoft documentation itself and made some changes to fit my needs.


private void GetRequestStreamCallback(IAsyncResult asynchronousResult)
{
 HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
 System.IO.Stream postStream = request.EndGetRequestStream(asynchronousResult);
 string strId = "My Id";
 string strName = "My Name";
 string postData = "userid=" + strId;
 postData += ("&username=" + strName);
 byte[] byteArray = System.Text.Encoding.UTF8.GetBytes(postData);
 // Write to the request stream.
 postStream.Write(byteArray, 0, postData.Length);
 postStream.Close();
 // Start the asynchronous operation to get the response
 request.BeginGetResponse(new AsyncCallback(GetResponseCallback), request);
}

You can see that in callback method, I grabbed the request object that was passed as state to the method call. Then I constructed data that I need to pass with the request that needed to be sent as POST. And then made another async call BeginGetResponse to submit the data and get the response.

Now lets look at what is this callback method for response.


private void GetResponseCallback(IAsyncResult asynchronousResult)
{
 HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
 HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);
 Stream streamResponse = response.GetResponseStream();
 StreamReader streamRead = new StreamReader(streamResponse);
 string responseString = streamRead.ReadToEnd();
 // Close the stream object
 streamResponse.Close();
 streamRead.Close();
 // Release the HttpWebResponse
 response.Close();
 Action<string> act = new Action<string>(DisplayResponse);
 this.Dispatcher.BeginInvoke(act, responseString);
}

void DisplayResponse(string msg)
{
 GainersText.Text = msg;
}

Again I passed original HttpWebRequest object to the call method as state. In the call back method, you can grab the request object and then call EndGetResponse to get the resonse stream.

Thread Context and Invalid cross-thread access error

You will notice that in GetResponseCallback method I have called BeginInvoke method on Dispatcher thread. This is very important if you are planning on doing any UI manipulation in the call back methods. The call back methods are invoked on a thread that are separate from the UI thread that initiated the request. So if you try to access any UI element in this callback you will get the following exception thrown.


An unhandled exception ('Unhandled Error in Silverlight Application 
Code: 4004    
Category: ManagedRuntimeError       
Message: System.UnauthorizedAccessException: Invalid cross-thread access.
   at MS.Internal.XcpImports.CheckThread()
   at System.Windows.DependencyObject.SetValueInternal(DependencyProperty dp, Object value, 
   Boolean allowReadOnlySet, Boolean isSetByStyle, Boolean isSetByBuiltInStyle,
   PropertyInvalidationReason reason)
   at System.Windows.DependencyObject.SetValueInternal(DependencyProperty dp, Object value)
   at System.Windows.DependencyObject.SetValue(DependencyProperty dp, Object value)
   at System.Windows.Controls.TextBlock.set_Text(String value)
   at SilverGrid.Views.Stocks.GetResponseCallback(IAsyncResult asynchronousResult)
   at System.Net.Browser.BrowserHttpWebRequest.<>c__DisplayClassd.
    <InvokeGetResponseCallback>b__b(Object state2)
   at System.Threading._ThreadPoolWaitCallback.WaitCallback_Context(Object state)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, 
   ContextCallback callback, Object state)
   at System.Threading._ThreadPoolWaitCallback.PerformWaitCallbackInternal
   (_ThreadPoolWaitCallback tpWaitCallBack)
   at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback(Object state)     
') occurred in iexplore.exe [7532].

Therefore it is important that from the callback method, you invoke an action request on Dispatcher thread of UI.

 

Views: 19415

Tags:

Silverlight

Silverlight Cross Domain Web Service Access Error - This could be due to attempting to access a service in a cross-domain way without a proper cross-domain policy in place

by Naveen 9. March 2010 08:37

Here is some error that most of Silverlight developers run into at some point.


An error occurred while trying to make a request to URI 
'http://nave-pc/SilverGridWeb/GridDataService.asmx'.
This could be due to attempting to access a service in a cross-domain way 
without a proper cross-domain policy in place, or a policy that is unsuitable 
for SOAP services. You may need to contact the owner of the service to publish 
a cross-domain policy file and to ensure it allows SOAP-related 
HTTP headers to be sent. This error may also be caused by using internal types 
in the web service proxy without using the InternalsVisibleToAttribute attribute. 
Please see the inner exception for more details.

I had developed cross-domain access web services for Silverlight in the past and all work like a charm. This morning I ran into this issue again while developing a new web service for a new Silverlight application. I knew that I needed to add CrossDomain.xml or ClientAccessPolicy.xml at root of my web application. So I copied those files from existing application to this new one. To my surprise it did not resolve the issue. I tried all kind of tricks and options but nothing seemed to help. Finally I decided to look at Silverlight documentation and see if there is anything new that has been done for Silverlight 3. Last time I did this was for a Silverlight 2.0 application. I could not find anything different in the description of what needed to be done. But then there was something in the sample XML file content for these files that caught my eye and looked different that what I had.


<allow-from http-request-headers="SOAPAction" >

Notice the underlined section. Previously the value in the allowed headers used to be *. Well, that does not seem to work any more. So I replaced it and everything worked fine.

There are some other important points I am going to discuss in this post. A lot of users do not seem to be clear where these cross domain policy files should be placed.

Location of CrossDomain.xml and ClientAccessPolicy.xml

As the documentation states, these should be placed at the root of the application. Although the statement is very clear but it causes lot of confusion about what is root? There are two ways you create a site in IIS, Virtual Directory and Web Application. So if you have a web site foo.com created as a web site in IIS, then the folder containing the content of this site is root of the application. So your policy files go in that folder. If you have created a virtual directory Bar under this web site where your web service is hosted, then the root of the site is still foo.com and not foo.com/bar. To verify it, open IIS log of your application and look for entries for Crossdomain.xml and ClientAccessPolicy.xml. From those entries you can figure out where those files should be located. If the caller is not finding those files, then you should 404 errors in your log file. For example here are entries from my log file.


1.17.30.170 GET /clientaccesspolicy.xml - 80 - 1.17.30.162  404 0 2 1
1.17.30.170 GET /crossdomain.xml - 80 - 1.17.30.162 404 0 2 1

This is very important. If you are hosting your web service in a web application that is created as a virtual directory in Default Web Site then you need to copy these files in wwwroot folder or whatver folder is configured to be default folder for your IIS installation. Copying policy files in your virtual directory is not going to help. You can also verify the location by looking at traffic in fiddler for your web service access.

Content for CrossDomain.xml and ClientAccessPolicy.xml

I have copied the content of these two files below. These files work for me on my my servers for cross domain access from silverlight.

ClientAccessPolicy.xml


<?xml version="1.0" encoding="utf-8"?>
<access-policy>
	<cross-domain-access>
		<policy>
			<allow-from http-request-headers="SOAPAction ">
				<domain uri="*"/>
			</allow-from>
			<grant-to>
				<resource path="/" include-subpaths="true"/>
			</grant-to>
		</policy>
	</cross-domain-access>
</access-policy>

CrossDomain.xml


<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
	<allow-http-request-headers-from domain="*" headers="SOAPAction,Content-Type"/>
</cross-domain-policy>

 

Views: 8032

Tags:

WCF | Silverlight | Web Service | WCF | Web Service

How to display custom tool tips in Silverlight Charts?

by Naveen 3. March 2010 11:49
custom tool tip in silverlight charts

Download Sample Projects (28.22 kb)

In my previous post, How to set silverlight column chart style programatically", I discussed one of the customizations of chart styles. In this post I will discuss one more customization of Silverlight charts rendering. This is about customizing display of Tooltip display on charts. If you look at default tool tip display, they are limited to displaying some combination of Independent and Dependent value. In some cases, that information is sufficient. But you may have cases where you want your tool tips to be verbose to convey more information about the data point that was used to render that point or column etc.

Template is the key

First and foremost concept that you will need to understand is how a chart actually gets rendered. Who decided the layout of various components of a chart display. Like any other Silverlight control, its the control template that defines how to chart is going to be rendered. So to customize the dispplay of Silverlight control, you can create a new template or take the default template and make modifications to it to come up with your own display scheme. Now you are asking from where can you get the default template for various chart types. The answer to it is Silverlight Toolkit source code. If you look in Charting/DataPoint folder of Controls.DataVisualization.Toolkit project, you will find template files for all chart types.

Customize Tooltip For Chart

Let us get started. For this discussion I picked Column type chart. Here are the steps that I followed to create a new template file for my column charts.

  • Add a new resource dictionary file in your project. In sample project I added ColumnChartStyle.xaml file under Assets folder.
  • Open ColumnDataPoint.xaml file from DataPoint folder from tool kit source. Copy the content of this file into your resource file.
  • Make sure that you change the build action of your resource file to Resource from Page
  • Assign a key to your style as shown below. You can pick any unique name. You are going to use the key when we apply this new template and style to our column charts.
    
    <Style TargetType="charting:ColumnDataPoint" x:Key="ByteBlocksColumns">
    
    
  • Open the XAML file where you have added chart that you want to display. In the sample project, it is in Home.xaml. And then assign DataPointStyle property to point to the static resource that we created from default implementation of ColumnDataPoint. And make sure that you use the key name that you used in the resource file. Following snippet shows how I did it in sample project.

    
    <chartingToolkit:Chart Title="Fruit Supply and Demand" 
       x:Name="FruitChart" 
       Width="500" 
       Height="350">
     <chartingToolkit:Chart.Series>
      <chartingToolkit:ColumnSeries
    		DataPointStyle="{StaticResource ByteBlocksColumns}"
            Title="Fruit Supply"
            IndependentValueBinding="{Binding Name}"
            DependentValueBinding="{Binding Supply}"/>
      </chartingToolkit:Chart.Series>
    </chartingToolkit:Chart>
    
    

Now you should be able to compile and run your project. We have not done any customization of tool tip yet. At this point you should be able to run the project with default template.

TooltipService and Tooltip

If you look near bottom of ColumnChartStyle.xaml file, you will find following snippet of code.


<ToolTipService.ToolTip>
 <ContentControl Content="{TemplateBinding FormattedDependentValue}"/>
</ToolTipService.ToolTip>

This is default implementation of how and what is displayed in tool tip. So you can see that by default only DependentValue is displayed. So this is the place where you will need to make changes to customize the display of tooltip for chart. If you are only interested in making some minor changes like adding some static text or adding display of dependent value as well, you can make a change as below.


<ToolTipService.ToolTip>
 <StackPanel Orientation="Horizonal">
 <ContentControl Content="{TemplateBinding FormattedDependentValue}"/>
 <TextBlock Text="-" />
  <ContentControl Content="{TemplateBinding FormattedIndependentValue}"/>
 </StackPanel Orientation="Horizonal">
</ToolTipService.ToolTip>

Customizing Tooltip Display at run time

In the sample project, I have implemented a use case where I want to create tool tip display at run time. What this means is that content of tool tip is being constructed based on some input from the existing data that is bound to that column. So in the template I am going to make some changes as shown below.


<ToolTipService.ToolTip>
<StackPanel Orientation="Horizontal">
<ContentControl Content="{Binding Id, Converter={StaticResource FruitConverter}}"/>
</StackPanel>
</ToolTipService.ToolTip>

In the snippet above you will see use of two things. One is that I am binding the content to the actual data object that was used to render that point. Second is use of converter. I am passing "Id" of the object as parameter to the converter. And in the converter I do some mock query to get more data. Following code shows how I constructed text of tool tip.


public class FruitSupplyToolTipConverter : IValueConverter
{
 public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
 {
  return GetToolTip(int.Parse(value.ToString()));
 }

 public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
 {
  return value;
 }

 object GetToolTip(int id)
 {
  var supply = MockData.FruitSupply.GetSupply();
  var query = from item in supply where item.Id == id select item;
  var items = query.ToList();
  if (items.Count == 0)
  {
   return string.Empty;
  }
  return CreateToolTip(items[0]);
 }

 object CreateToolTip(FruitSupply supply)
 {
  var panel = new StackPanel();
  panel.Orientation = Orientation.Vertical;
  var tipTextBlock = new TextBlock();
  tipTextBlock.Inlines.Add(new Run { Text = supply.Name });
  tipTextBlock.Inlines.Add(new LineBreak());
  tipTextBlock.Inlines.Add(new Run { Text = string.Format("Supply: {0}", supply.Supply)});
  tipTextBlock.Inlines.Add(new LineBreak());
  panel.Children.Add(tipTextBlock);
  var hlink = new HyperlinkButton();
  hlink.Content = "For more informattion Goto http://www.ByteBlocks.com";
  hlink.NavigateUri = new Uri("http://www.byteblocks.com");
  panel.Children.Add(hlink);
  return panel;
  }
}

You could argue that instead of going to the extent of using converter to build a tool tip text, I could have added another property to data object that contains the text and then bind tool tip to that property. That would have worked perfectly as well. But for demonstrating how you can construct tool tip text based on some other pieces of data or if tool tip content changes rapidly with time as well, then you need to access it at run time.

I hope this should give you good starting point to go nuts on more nifty tool tips.

 

Views: 12195

Tags: , , ,

Charting | Silverlight

Smart Phones Poll

What smart phone do you currently own?





Show Results

Month List

Powered by BlogEngine.NET 2.0.0.49
Theme by Naveen Kohli