Introduction to Telerik RadControls for Metro (Bar Chart)

Telerik is one of the lead providers of .NET components and development tools. At work, my group utilizes a lot of Telerik products, so when I learned that Telerik is jumping into metro style application bandwagon, I would like to try it.

The first component that I look at today is a chart component. When we talk about Line-Of-Business (LOB) application, besides grids and forms, charts are other type of controls that are used often. WinRT (either XAML or HTML) provides vector-based drawing API that we can used to draw a chart, but it is better to be able to utilize reusable components for common charts like bar, pie, or line charts.

In this post, I will create a simple bar chart using Telerik chart control for metro in XAML. As always, I will reuse my Person and SamplePeople classes that I used in other posts about Windows 8. In this example, I will plot number of my customers by gender in each state using bar chart.

First, let’s download Telerik RadControls for Metro beta here.

image

After I create a C#/XAML blank app and add references to Telerik libraries as shown in the above screenshot, I start by adding telerik namespace and a RadCartesianChart control which I can use to create several type of charts including bar chart. RadCartesianChart control uses the Cartesian coordinate system to plot series of data within X and Y axes.

image

Here is the code in Main.xaml

        <telerik:RadCartesianChart x:Name="radChart" Grid.Row="1" Margin="120 0 0 0" PaletteName="DefaultDark">
            <telerik:RadCartesianChart.HorizontalAxis>
                <telerik:CategoricalAxis/>
            </telerik:RadCartesianChart.HorizontalAxis>
            <telerik:RadCartesianChart.VerticalAxis>
                <telerik:LinearAxis/>
            </telerik:RadCartesianChart.VerticalAxis>            
        </telerik:RadCartesianChart>    

Inside the RadCartesianControl, I define two axes, a horizontal categorical axis which will arrange the plotted data points in defined categories (e.g., name of state) and linear vertical axis which uses the numeric value (e.g., number of customers in each state).

In the code-behind, I get the sample people and group them by state, so I can count them. Then I create two bar series, one for male and another for female, and bind category to Name (StateData.Name) and value to Count (StateData.Count). I also need to specify the series combined mode. There are four modes, None, Cluster, Stack, and Stack100. Cluster makes the series combined next to each other while stack forms stacks and so on.

Here is the code-behind in Main.xaml.cs

    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
        }

        /// <summary>
        /// Invoked when this page is about to be displayed in a Frame.
        /// </summary>
        /// <param name="e">Event data that describes how this page was reached.  The Parameter
        /// property is typically used to configure the page.</param>
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            SamplePeople.BuildSamplePeople();

            AddSeries("Male");
            AddSeries("Female");
        }

        private void AddSeries(string gender)
        {
            var peopleByStates = from p in SamplePeople.People
                                 where p.Gender == gender
                               group p by p.ResidenceState into g
                               orderby g.Key
                               select new { State = g.Key, People = g };
           
            var series = new BarSeries();
            series.CombineMode = Telerik.Charting.ChartSeriesCombineMode.Stack;
            series.CategoryBinding = new PropertyNameDataPointBinding("Name");
            series.ValueBinding = new PropertyNameDataPointBinding("Count");
            

            var itemSources = new List<object>();
            foreach (var state in peopleByStates)
            {
                var item = new StateData { Name = state.State, Count = state.People.Count() };
                itemSources.Add(item);
            }

            series.ItemsSource = itemSources;
            radChart.Series.Add(series);
        }
    }

    public class StateData
    {
        public double Count { get; set; }
        public string Name { get; set; }
    }    

Let’s run the app and see how it looks. The first screenshot is the bar chart in Cluster mode and the second one is the bar chart in stack mode.

image

image

As you see, just couple lines of code, I now have nice looking bar chart in my app. There are a lot more components in the beta download including, DatePicker, Slider, DropDownList, and other chart types like pie chart and so on. I am going to post about them in the future. As of now, enjoy coding!

Adding Auto-suggestion to Metro Style App Search Contract

As promised on my post about adding search to C# metro style app, I will enhance the sample project from the first post by adding auto-suggestion (auto-complete) capability.

If you have already implemented search contract on your metro style app project, adding auto-suggestion is just a matter of registering an additional event handler (yes, WinRT API is really that easy).

Anyway, let’s get started.

First, I register a SuggestionRequested event handler in the OnLaunced method.

        protected override void OnLaunched(LaunchActivatedEventArgs args)
        {
            SamplePeople.BuildSamplePeople();

            SearchPane.GetForCurrentView().SuggestionsRequested += OnSuggestionsRequested;

            // Do not repeat app initialization when already running, just ensure that
            // the window is active
            if (args.PreviousExecutionState == ApplicationExecutionState.Running)
            {
                Window.Current.Activate();
                return;
            }

            if (args.PreviousExecutionState == ApplicationExecutionState.Terminated)
            {
                //TODO: Load state from previously suspended application
            }

            // Create a Frame to act navigation context and navigate to the first page
            var rootFrame = new Frame();
            if (!rootFrame.Navigate(typeof(MainPage)))
            {
                throw new Exception("Failed to create initial page");
            }

            // Place the frame in the current Window and ensure that it is active
            Window.Current.Content = rootFrame;
            Window.Current.Activate();
        }

Second, I reuse the code in SearchResult page in the first post and put it in OnSuggestionRequested method.

        private void OnSuggestionsRequested(SearchPane sender, SearchPaneSuggestionsRequestedEventArgs args)
        {
            string queryText = args.QueryText.ToLower();

            var suggestions = SamplePeople.People
                .Where(p => p.LastName.ToLower().Contains(queryText.ToLower())
                        || p.FirstName.ToLower().Contains(queryText.ToLower())
                        || p.ResidenceState.ToLower().Contains(queryText.ToLower()));

            foreach (var suggestion in suggestions.Select(p => string.Format("{0}, {1} ({2})", p.LastName, p.FirstName, p.ResidenceState)))
            {
                args.Request.SearchSuggestionCollection.AppendQuerySuggestion(suggestion);
            }
        }

The important part is how I add the suggestion to the SearchSuggestionCollection. The collection requires string, but it depends on the app to put the meaningful strings as suggestions. As my query is filtering either last name, first name, or state, I combined them together as a suggestion.

image

image

image

As you can see, Windows 8 also helps by highlighting the search term in those suggestions, so what you choose as suggestion strings will determine how easy to search on your application.

Hope you enjoy this short post. At the time of this writing, we already know that Windows 8 will be available (GA) on October 26th. Let’s get ready soon.  Enjoy coding!

Join NoSQL movement with RavenDB – Part 2 (Embedded, InMemory, and Management Studio)

This is the second post continued from the post,  Join NoSQL movement with RavenDB – Part 1.  Part 1 showed how easy it is to use RavenDB by embedding it into your console application using NuGet package manager.

This post, I will embed RavenDB to a normal Web Form application. After creating an empty web application, I just go to NuGet package manager like the previous post and install RavenDB Embedded.

imageimage

The screenshots above show the solution before and after RavenDB Embedded has been installed. Besides the required RavenDB libraries in References, you should see Raven.Studio.Xap, which I didn’t mention last time. The xap file allows me to use the Management Studio, which is a silverlight client that let you manage the data in a RavenDB server instance similar to a typical RDBMS client such as SQL Server Management Studio.

Next step is to continue building the application. I add a normal web form page. I will just put a normal GridView into the page with AutoGenerateDeleteButton set to true and a RowDeleting event handler. I also add a model class, Person (which I also use in the post, Adding Search to your C# Metro Style App ).

image

In the ListPeople.aspx code-behind page, I initialize the RavenDB instance as well as adding documents . I should have done this in Global.asax in non-demo application Winking smile.

    public partial class ListPeople : System.Web.UI.Page
    {
        static IDocumentStore ravenInstance;        

        protected void Page_Load(object sender, EventArgs e)
        {
            if (!Page.IsPostBack && ravenInstance == null){           
                // Initialize new RavenDB Memory Instance with EmbeddedHttpServer                
                ravenInstance = new EmbeddableDocumentStore { RunInMemory = true, UseEmbeddedHttpServer = true };                
                ravenInstance.Initialize();

                // Build Sample Data
                SamplePeople.BuildSamplePeople();
                
                using(var session = ravenInstance.OpenSession())
                {
                    foreach (var person in SamplePeople.People)
                    {
                        session.Store(person);
                    }
                    session.SaveChanges();
                }
                BindPeopleGrid(SamplePeople.People);
            }
        }        

        protected void PeopleGrid_RowDeleting(object sender, GridViewDeleteEventArgs e)
        {
            using (var session = ravenInstance.OpenSession())
            {
                // Get Deleting Id
                var personId = e.Values[0].ToString();   
                             
                // remove from RavenDB
                var person = session.Load<Person>(personId);
                session.Delete(person);
                session.SaveChanges();

                // rebind the data from RavenDB
                var people = session.Query<Person>();
                BindPeopleGrid(people);
            }            
        }

        void BindPeopleGrid(IEnumerable<Person> people)
        {
            PeopleGrid.DataSource = people;
            PeopleGrid.DataBind();
        }
    }

This time you might notice that I used different configuration options from the last time. I wanted to run RavenDB instance in memory (of course this means every time an instance is created, it will be an empty database, so utilize it carefully). Instead of setting ConnectionString, I put RunInMemory and UseEmbeddedHttpServer equal to true. The UseEmbeddedHttpServer option will allow me to access the RavenDB instance externally or through the REST API.

The other interesting in the code is the PeopleGrid_RowDeleting method which handles deleting event when a Delete button/link is clicked. Now let me just run the application.

image

I can also run the RavenDB Management Studio to see what documents we have in the current RavenDB instance. I can do this by hitting http://localhost:8080/ (RavenDB might use another port on your machine if 8080 is already used by another process), and I should see the nice Silverlight client. I can hover the document to see what my data looks like (i.e., JSON document). Please note that the value in Id property is automatically given by RavenDB when the person instance is being stored. For more information about different key generation options, please check http://ravendb.net/docs/theory/document-key-generation.

image

I clicked the Delete button/link in the GridView, and the document is deleted in RavenDB and on GridView.

image

image

In next RavenDB post (which I also promised last time), I will run RavenDB server in the console mode and show the RavenDB management studio which can be used to manage RavenDB server as well as see RavenDB in more detail. Enjoy coding!