Sony Arouje

a programmer's log

Archive for the ‘Silverlight’ Category

Scalable Silverlight app using MEF and Caliburn Micro

leave a comment »

In this post I am going to give a brief insight of my experiment with MEF and Caliburn Micro. I am always a big fan of plug-in application model. When I go through the MEF I was so impressed and want to try as it is similar to my favorite area (plugin model). As usual I used caliburn micro here as well.

The app I developed is just for demo purpose and there is no business value. In my app I display couple of user controls and all are loaded by MEF. The app also demonstrate the powerful event handling provided by Caliburn micro. With the help of MEF and Caliburn micro we can build a very powerful scalable silverlight app.

Below is the screen shot of my app

image 

As you can see my UI is not very fancy, because my intention was to try how MEF will work in conjunction with caliburn micro. The first two expanders wont do any job other than displaying some thing to user. The Display Text and Font selection will do some demonstration of Event publishing. The user selected Font properties will get applied to the Text in the Display Text expander.

I implemented an interface called IView to make all the view models satisfy MEF exports. Below is the interface.

namespace SilverlightClassLib.Common
{
    [InheritedExport]
    public interface IView
    {

    }
}

 

A blank interface decorated by and Attribute called InheritedExport. Which ever the class implements this interface will be considered for Exporting. You can get more details about this approach from Brad Abrams blog. In this demo all my viewmodels implemented IView interface. MEF will gather all my Exported ViewModels and Caliburn micro will intern load the View for the view model.

I compose my UI in MainPageViewModel.cs as shown below. To compose the ui you have to add reference to assembly System.ComponentModel.Composition and add using’s to System.ComponentModel.Composition.Hosting and System.ComponentModel.Composition

namespace MEFCaliburnMicroTracer.ViewModels
{
    public class MainPageViewModel:PropertyChangedBase
    {
        public MainPageViewModel()
        {
            var catalog = new PackageCatalog();
            catalog.AddPackage(Package.Current);
            var container = new CompositionContainer(catalog);
            container.ComposeParts(this);
        }

        [ImportMany(AllowRecomposition=true)]
        public ObservableCollection<IView> importedViews { get; set; }
    }
}

In the constructor we load the current xap file to MEF container. The exported part will get added to property which is decorated with ImportMany attribute. In this case it’s ImportedViews property. I set AllowRecomposition to true to load exported parts if we do any async loading of xap’s. In this case there is no parameter required as we are not doing any async loading.

A Listbox In the MainPageView is binded to importedViews property. This listbox is responsible of displaying all my Views.

The greatest advantage of MEF is, we can add or remove new functionality without affecting the existing modules. And the powerful EventAggregator in Caliburn micro will help to enable loosely coupled interaction between the modules.

Download Source

Written by Sony Arouje

October 20, 2010 at 7:38 pm

Image uploading & Retrieving – Silverlight and WCF

with 9 comments

In several forums I saw people asking about how we can upload Images or files to server using silverlight. So I thought of writing one to demonstrate how we can achieve it. I become a big fan of caliburn micro and I used it in this app as well.

In this demo app I demonstrating both approach of accessing WCF service – Proxy less and Proxy approach. I personally like Proxy less approach so I cannot avoid it here also.

Let’s go through my solution structure

image

Repository: This project contains entities and persistence classes. I made it as simple as possible in this demo, so all the persistence related stuff is in the same project.

WCFService: Project contains the service implementation

WCFService.Interfaces: project contains the service contracts.

WCFHost: Project host the WCF service.

In Silverlight folder I have a Project called ServiceLinkProject, that is a project that has link to entity files. It is used for Proxy less WCF communication. In this demo I used my generic repository mentioned in my previous post.

There is nothing much to explain here except the valueconverter I used in the xaml page. I save and retrieve images as byte arrays. But silverlight’s Image control will not be able to render byte arrays. So wrote a Converter inherited from IValueConverter. Let’s see how am using it.

First I created an instance of the converter.

    <navigation:Page.Resources>
        <converter:ByteToImageConverter x:Name="binaryConverter"/>
    </navigation:Page.Resources>

 

Now use this converter while binding the byte[] to image.

<Image x:Name="thumbNail"  Width="100" Height="100" VerticalAlignment="Center" Source="{Binding ImageInBytes,Converter={StaticResource binaryConverter}}"></Image>


I think this project doesn’t requires much explanation. If any one has any questions then am happy to help you out.

Download Source code

Written by Sony Arouje

October 16, 2010 at 4:04 am

Proxy less Silverlight – WCF Async communication

with 12 comments

In this post I am going to explain how a silverlight application can communicate with WCF service without any proxy. I wanted to establish this communication without any autogenerated code because am not a fan of proxies generated by VS. If you want VS to create good autogenerated code then probably invest some time in learning T4 templates. Anyway I haven’t done any research in T4 templates, so let’s do every thing by hand.

Here is my requirement, I have to show a list of customer in my Silverlight app. Keep in mind it just an experiment, so no db involved in this app. For simplicity I hosted my wcf service in IIS.

Let’s straight to the code.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using DataModel;
namespace ServiceContracts
{
    [ServiceContract]
    public interface ICustomerService
    {
        [OperationContract]
        ICollection<Customer> GetCustomerList();
    }

}

I only have one function in the service contract, a function return a collection of Customer class. Customer class is a just a C# class that has only two properties as shown below

using System.Runtime.Serialization;
namespace DataModel
{
    [DataContract]
    public class Customer
    {
        [DataMember]
        public int CustomerId { get; set; }

        [DataMember]
        public string CustomerName { get; set; }
    }
}
Let’s give some implementation to our Service Contract
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ServiceContracts; //assembly consist service contracts
using DataModel; //assembly contains data contracts
namespace ServiceLayer
{
    public class CustomerService:ICustomerService
    {
        public ICollection<Customer> GetCustomerList()
        {
            List<Customer> customers = new List<Customer>();
            Customer cust = new Customer();
            cust.CustomerId = 1;
            cust.CustomerName = "sony";

            customers.Add(cust);
            return customers;
        }

        }

}

 

Now our service is ready to host, here I use IIS to host it. But how does Silverlight can utilize the Function we implemented, because I haven’t implemented Async methods. You might know that Silverlight can only work in Async mode. There are several ways of calling the above implemented service in Silverlight. One way is adding Service reference and leave it to VS to create the proxy with Async code generation. Another approach is use Castle Windsor to host the service in Async mode. Some how I didn’t like both the approach so I was trying for a better approach. My search ended up in a blog to achieve the Async communication without much modification to my Service code.

Here is the approach I was looking at. Create a new Service contract with Async functions and make it an alias to my original ICustomerSerivce

[ServiceContract(Name = "ICustomerService")]
public interface ICustomerServiceAsync
{
    [OperationContract(AsyncPattern = true)]
    IAsyncResult BeginGetCustomerList(AsyncCallback callback, object state);

    ICollection<Customer> EndGetCustomerList(IAsyncResult result);
}

 

And use the above ICustomerServiceAsync to communicate to ICustomerService. This approach is pretty clean and we don’t want to add any Async methodology to our core service.

Below is my web.config of WCFService host.

<?xml version="1.0"?>
<configuration>

  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.serviceModel>
    <services>
      <service name="CustomerService">
        <endpoint address="" contract="ServiceContracts.ICustomerService" binding="basicHttpBinding"></endpoint>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
          <serviceMetadata httpGetEnabled="true"/>
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="true"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
 <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>  
</configuration>

 

As you see my service end point configuration I have not mentioned ICustomerServiceAsync. Let’s go through the silverlight client how we can communicate to our service.

private void button1_Click(object sender, RoutedEventArgs e)
{
    EndpointAddress endPoint = new EndpointAddress("http://localhost:63301/CustomerService.svc");
    BasicHttpBinding binding = new BasicHttpBinding();
    ICustomerServiceAsync customerService = new ChannelFactory<ICustomerServiceAsync>(binding, endPoint).CreateChannel();

    customerService.BeginGetCustomerList(a => 
    {
        try
        {
            ICollection<Customer> person = customerService.EndGetCustomerList(a);
        }
        catch (Exception ex)
        {
            throw ex;
        }

    }, customerService);

}

In a button click am calling the service.  Here I used the ICustomerAsync to create the channel. Ayende’s blog will give you more details.

You might think how I could able to reference ICustomerServiceAsync and Customer classes in my Silverlight client. What I did here is I created a Silverlight class library and add ICustomerAsync and Customer class as a link. In VS we can do it by selecting add existing item and rather than clicking on the Add button, click on the arrow on the right side of the Add and select as link from the option.

In the above client code I used lambda expression to call the service. You can also use a anonymous delegate or Callback method to achieve the same.

One important thing you need to add to our WCFService host project is clientaccesspolicy.xml, other wise Silverlight client will not be able to communicate and throws Security exception. Below is the policy file

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

 

To test my connection and exceptions I used a Winform application. Silverlight wont give proper error details.

Download the code here

 

 

Written by Sony Arouje

October 1, 2010 at 7:14 pm

Persisting Combo box SelectedItem – Caliburn Micro

with 7 comments

In this post I am going to explain how to persist Selected Item in a Combo box. In my application I have several screens and the user can navigate between them. I need to persist the Combobox’s Selected Item and bind it back when user navigate back to the screen. Here persisting is not db level persistence.

My application is based on Caliburn Micro, a wonderful lightweight MVVM framework.

To persist the selections, I wont create new ViewModel when ever the user clicks on the Navigation button. Only once the instance of the view model will get created. The following code shows the implementation, very simple approach.

FontPropertiesViewModel _fontPropertiesViewModel;
public void GetFontProperties()
{
    if (_fontPropertiesViewModel == null)
        _fontPropertiesViewModel = new FontPropertiesViewModel();
    ActiveScreen = _fontPropertiesViewModel;
}

Let’s examine the xaml file

<UserControl x:Class="MVVMTracer.Pages.Views.FontPropertiesView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
    xmlns:ca="clr-namespace:Caliburn.Micro;assembly=Caliburn.Micro"
    mc:Ignorable="d"
    d:DesignWidth="640" d:DesignHeight="480">
    
    <Grid x:Name="LayoutRoot" Background="Transparent" Margin="0,0,10,0">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="25"/>
                <RowDefinition Height="35"/>
                <RowDefinition Height="30"/>
                <RowDefinition Height="30"/>
                <RowDefinition Height="30"/>
                <RowDefinition Height="30"/>
                <RowDefinition Height="35"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="150"/>
                <ColumnDefinition Width="0.555*"/>
            </Grid.ColumnDefinitions>
            <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="Text" VerticalAlignment="Center" FontSize="13.333" Margin="10,0,0,0" Foreground="#FF0F5DA7" Grid.ColumnSpan="2" Width="297"/>
            <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="Font Type" Margin="10,0,0,0" Grid.Row="2" FontSize="11" VerticalAlignment="Center"/>
            <ComboBox x:Name="FontType" Grid.Row="2" Grid.Column="1" VerticalAlignment="Center" FontSize="11" SelectedItem="{Binding SelectedFontType}">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="SelectionChanged">
                        <ca:ActionMessage MethodName="FontTypeSelectionChanged">
                            <ca:Parameter Value="{Binding ElementName=FontType,Path=SelectedItem}"></ca:Parameter>
                        </ca:ActionMessage>
                    </i:EventTrigger>
                </i:Interaction.Triggers>                
            </ComboBox>
            
            <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="Font Size" Margin="10,0,0,0" Grid.Row="3" FontSize="11" VerticalAlignment="Center"/>
            <ComboBox x:Name="FontSize" Margin="0,0,0,0" Grid.Row="3" FontSize="11" HorizontalAlignment="Left" VerticalAlignment="Center" Width="53" Grid.Column="1" SelectedItem="{Binding SelectedFontSize}">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="SelectionChanged">
                        <ca:ActionMessage MethodName="FontSizeSelectionChanged">
                            <ca:Parameter Value="{Binding ElementName=FontSize,Path=SelectedItem}"></ca:Parameter>
                        </ca:ActionMessage>
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </ComboBox>
                        
            <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="Font Style" Margin="10,0,0,0" Grid.Row="4" VerticalAlignment="Center" FontSize="11"/>
            <ComboBox x:Name="FontStyle" Grid.Row="4" Grid.Column="1" FontSize="11" VerticalAlignment="Center" SelectedItem="{Binding SelectedFontStyle}">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="SelectionChanged">
                        <ca:ActionMessage MethodName="FontStyleSelectionChanged">
                            <ca:Parameter Value="{Binding ElementName=FontStyle,Path=SelectedItem}"></ca:Parameter>
                        </ca:ActionMessage>
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </ComboBox>
            <Button x:Name="Done" Content="Done"  Grid.Row="5" Grid.Column="1" Width="70" HorizontalAlignment="Right" d:LayoutOverrides="Height" VerticalAlignment="Bottom"/>
        </Grid>
    </Grid>
</UserControl>

If you examine the xaml you can see that the selected item of the combo boxes are binded to different properties, also I use ActionMessaging to notify the view model when ever a selection change happen in the Comboboxes. You might wonder why am using ActionMessaging rather than I could bind SelectedItem in two way mode. Yes I tried it first but unfortunately the Selected Item is not showing when user navigates back to the page.

Time to go through the view model

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Caliburn.Micro;
using MVVMTracer.MockServices;
using EmblemDesigner.Controls;

namespace MVVMTracer.Pages.ViewModels
{
    public class FontPropertiesViewModel:PropertyChangedBase
    {
        public FontPropertiesViewModel()
        {
            this.FontType = FontServices.GetFontFamily();
            this.FontStyle = FontServices.GetFontStyle();
        }

        private List<string> _fontType;
        public List<string> FontType
        {
            get { return _fontType; }
            private set 
            {
                _fontType = value;
                NotifyOfPropertyChange(() => FontType);
            }
        }
        private string _selectedFontType;
        public string SelectedFontType
        {
            get { return _selectedFontType; }
            private set
            {
                _selectedFontType = value;
            }
        }
        public void FontTypeSelectionChanged(object selectedItem)
        {
            this.SelectedFontType = selectedItem as string;
        }

        private List<string> _fontSize;
        public List<string> FontSize
        {
            get { return _fontSize; }
            private set
            {
                _fontSize = value;
                NotifyOfPropertyChange(() => FontSize);
            }
        }
        private string _selectedFontSize;
        public string SelectedFontSize
        {
            get { return _selectedFontSize; }
            private set
            {
                _selectedFontSize = value;
            }
        }
        public void FontSizeSelectionChanged(object selectedItem)
        {
            this.SelectedFontSize = selectedItem as string;
        }


        private List<string> _fontStyle;
        public List<string> FontStyle
        {
            get { return _fontStyle; }
            private set
            {
                _fontStyle = value;
                NotifyOfPropertyChange(() => FontStyle);
            }
        }
        private string _selectedFontStyle;
        public string SelectedFontStyle
        {
            get { return _selectedFontStyle; }
            private set
            {
                _selectedFontStyle = value;
            }
        }
        public void FontStyleSelectionChanged(object selectedItem)
        {
            this.SelectedFontStyle = selectedItem as string;
        }
    }
}

Let’s take an eg. of FontType to understand what I am doing here. In the View one of my Combo box name is FontType. Caliburn Micro is intelligent enough to bind the FontType properties in the view model to the Combo box with name FontType in the view. Really great. If you run the application, you can see the FontType combo box is populated with the fonts we added to the FontType properties.

But it’s not enough to persist the user selection. To do so we need to add some more code to the view model. You might have noticed in xaml that the ActionMessage of FontType combo is attached to FontTypeSelectionChanged. When ever the user change selection it will get notified to FontTypeSelectionChanged function in the view model. This function will intern update the SelectedFontType property. The selected SelectedFontType property is binded to FontType’s Combobox’s SelectedItem.

Below diagram shows the communication between the view and the view model what I explained above.

image

One thing I noticed here is the Auto Implemented or Automatic Properties wont work here.

If any better approach pls update me.

Written by Sony Arouje

September 21, 2010 at 12:15 pm

An Experiment In Caliburn Micro

In this blog I will explain my experiment with Caliburn Micro. The business logic of this app is

  • It should display a list of images
  • Add the image to the canvas when the user selected an image
  • Drag the Image and Position the Image where ever the user required
    For dragging/rotation/resize the image I used an Adorner control. You can get more details about the control here.

I have to add Images displayed in a list box to a canvas. Pretty simple 🙂 and helped me a lot to learn Caliburn Micro. Before going further I wanted to say that the app may not be a full MVVM model, you will come to know as you proceed. I am working on it to make it completely MVVM complaint.

Below is the screen shot of the Silverlight app.

image

Two buttons are there on the top.

  • Show Text: button will load User control that will have a UI with some text box and combo box.
  • Image Controls: Button will load the user control displayed above.

Bare with my naming, I am very poor in it.

When the user clicks on any of these button we need to show the respective View in the left hand side. I used Caliburn Micro as my MVVM frame work.

My project structure is below

image

  • Views: Contains my XAML files
  • ViewModels: contains my view model of the views
  • ValueObject: contains the value object class I used in this app
  • Messages: I used EventAggregator provided by Caliburn Micro to enable messaging between ViewModels. This folder contains the Class I used for messaging between ViewModels.
  • Controls: contains custom controls I used in this app.
  • Adorner: contains the Adorner controls
    Let’s jump into the code

      TabView

    This is the main view which calls other other user controls

    XAML
<navigation:Page x:Class="MVVMTracer.Views.TabView" 
           xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
           xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
           xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
           xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
           xmlns:tl="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Layout.Toolkit"
           xmlns:we="clr-namespace:MVVMTracer.Controls"
           mc:Ignorable="d"
           xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
           d:DesignWidth="640" d:DesignHeight="480"
           Title="TabView Page">
    <UserControl.Resources>
        <DataTemplate x:Key="shapeTemplate">
            <we:ControlBase Width="{Binding Width}" Height="{Binding Height}"/>
        </DataTemplate>
    </UserControl.Resources>
    <Grid x:Name="LayoutRoot">
        <Grid.RowDefinitions>
            <RowDefinition Height="40"></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="200"></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>
        
        <StackPanel Grid.Row="0" Orientation="Horizontal" Height="30">
            <Button x:Name="ShowTextControls" Content="Show Text"></Button>
            <Button x:Name="ShowImageControls" Content="Image Controls"></Button>
        </StackPanel>
        
        <tl:TransitioningContentControl Grid.Row="1" Grid.Column="0" x:Name="ActiveScreen"></tl:TransitioningContentControl>

        <we:CustomItemsCollection x:Name="DisplayControls"  Grid.Row="1" Grid.Column="1">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Canvas  Background="AliceBlue"/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        </we:CustomItemsCollection>
    </Grid>
</navigation:Page>

In the above xaml you might notice that I used TransitioningContentControl. This is the control I am going to use to show different UserControl based on the user request. By the way TransitioningContentControl is part of Silverlight Tool kit,

Here I used a CustomItemsCollection to add my dynamically added controls. CustomItemsCollection is a control derived from ItemsControl. I will show the implementation of it later.

TabViewModel.cs

 

using System;
using System.Net;
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;
using Caliburn.Micro;
using MVVMTracer.Adorners;
using MVVMTracer.Controls;
using MVVMTracer.Messages;
namespace MVVMTracer.ViewModels
{
    public class TabViewModel:PropertyChangedBase,IHandle<Messages.ImageSelectionChanged>
    {
        public TabViewModel()
        {
            EventAggregatorContainer.EventAggregator.Subscribe(this);
        }
        private object _activeScreen;
        private Adorner _adorner = new Adorner();
        private Canvas _parentCanvas = new Canvas();
        public object ActiveScreen
        {
            get { return _activeScreen; }
            set
            {
                _activeScreen = value;
                NotifyOfPropertyChange(() => ActiveScreen);
            }
        }

        public void ShowTextControls()
        {
            ActiveScreen = new ShowTextViewModel();
        }

        public void ShowImageControls()
        {
            ShowImageControlViewModel imgViewModel = new ShowImageControlViewModel();
            ActiveScreen = imgViewModel;
        }
        public void Handle(Messages.ImageSelectionChanged message)
        {
            ControlBase ctrl = ShapeFactory.GetShape(ShapeType.Image, _parentCanvas, _adorner);

            ctrl.Source = message.CurrentImage;
            this.AddToUICollection(ctrl);
        }
        private void AddToUICollection(ControlBase control)
        {
            if (_displayControls == null)
            {
                _displayControls = new System.Collections.ObjectModel.ObservableCollection<UIElement>();
                _adorner.Height = 0;
                _adorner.Width = 0;
                _parentCanvas.Children.Add(_adorner);
                _displayControls.Add(_parentCanvas);
            }
            control.DrawControl();
            control.Height = 100;
            control.Width = 100;
            _parentCanvas.Children.Add(control);
            NotifyOfPropertyChange(() => DisplayControls);
        }
        private System.Collections.ObjectModel.ObservableCollection<UIElement> _displayControls;
        public System.Collections.ObjectModel.ObservableCollection<UIElement> DisplayControls
        {
            get { return _displayControls; }
            private set
            {
                _displayControls = value;
                NotifyOfPropertyChange(() => DisplayControls);
            }
        }




    }
}

The above code explains the ViewModel of TabView. As I mentioned in the beginning it may not completely satisfies MVVM pattern. I will explain the reason. As per my requirement I wanted to add Images to my Canvas and allow the user to reposition it.

To achieve the requirement I initially binded list of UIElement that consist of my Images to the CustomItemsCollection. But the issue I faced is I couldn’’t drag the image to different location. So I find out a work around. The work around is create a Canvas in Viewmodel and add the canvas to DisplayControls. Then add the images to the canvas object. By adding Canvas to DisplayControls will internally bind the Canvas object and its children to CustomItemsCollection in the View.

In this app I used EventAggregator to enable Messaging between ViewModels. To enable Messaging in CaliburnMicro the subscriber should Implement IHandle interface. You can see in the above code I implemented IHandle interface and subscribed to ImageSelectionChanged. Any publisher who publish ImageSelectionChanged message will be notified to TabViewModel.

The custom Control to display Image is not in MVVM structure.

You can find the Image listing control and other piece of codes in the uploaded source code.

You can download the code here

Written by Sony Arouje

September 9, 2010 at 7:06 pm

Callouts in Silverlight

with 4 comments

As per the project requirement I have to show some Callouts. I was thinking of creating it using paths and curves. It would have been a lot of work. But blend saved my time. Blend provides callouts and other shapes in toolbar, VS editor wont provide it in toolbar. Below xaml shows a callout with an Oval textbox (Oval textbox I mentioned in my earlier post).

Name Space: System.Windows.Shapes

XAML

<UserControl
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:ed="http://schemas.microsoft.com/expression/2010/drawing"
    xmlns:we="clr-namespace:Designer.Controls"
    mc:Ignorable="d"
    x:Class="Designer.Controls.CallOutOval"
    d:DesignWidth="640" d:DesignHeight="480">

    <Grid x:Name="LayoutRoot">
        <ed:Callout AnchorPoint="0,1.25" CalloutStyle="Oval" Fill="#FFF4F4F5" FontSize="14.666999816894531" Stroke="Black" HorizontalAlignment="Left" VerticalAlignment="Top">
            <ContentControl>
                <we:OvalTextBox Text="Your Text here" CornerRadius="50" BorderThickness="0" Background="Transparent"></we:OvalTextBox>
            </ContentControl>
        </ed:Callout>
    </Grid>
</UserControl>

Blend provides different callouts like Oval, Rectangle and Cloud. We are done with the Callout user control.

Written by Sony Arouje

August 30, 2010 at 5:38 pm

Image dragging and dropping in Silverlight

leave a comment »

In this sample code I am going to demonstrate how we can drag and drop an image from windows explorer to a Silverlight page.

To run the test we should have a page with an Image control. Lets call our Image control as ImgShow. In the xaml, set the AllowDrop property to true. Also add a drop event to the Image control. Once the drop event is added go to the code behind and add the below code to the event.

private void ImgShow_Drop(object sender, DragEventArgs e)
{
    if (e.Data.GetDataPresent(DataFormats.FileDrop))
    {
        FileInfo[] fi = (FileInfo[])e.Data.GetData(DataFormats.FileDrop);
        BitmapImage img = new BitmapImage();
        using (Stream fileStream = fi[0].OpenRead())
        {
            img.SetSource(fileStream);
        }
        ImgShow.Source = img;
    }
}

We are done with the application. Run the application and drag and drop a file from Windows explorer to ImgShow image control.

Written by Sony Arouje

August 25, 2010 at 4:26 pm

Posted in Silverlight

Silverlight Toolbar control

with 7 comments

In this post I am explaining how to create a basic toolbar in Silverlight. This toolbar has two parts

    • Toolbar panel
    • Toolbar item

Screen shot

image

ToolBar Panel

This user control holds all the Toolbar items. This control internally uses Stackpanel to organize the Toolbar items. Below is the XAML and code behind

XAML

<UserControl x:Class="Controls.ToolBarPanel"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
             Background="Transparent"
    d:DesignHeight="300" d:DesignWidth="400">
    
    <Grid x:Name="LayoutRoot" Background="Transparent">
        <StackPanel x:Name="itemHolder" Orientation="{Binding Orientation}" Background="Transparent"></StackPanel>
    </Grid>
</UserControl>

Code behind

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace Controls
{
    public partial class ToolBarPanel : UserControl
    {
        public event Click ToolBarItemClick;
        public ToolBarPanel()
        {
            InitializeComponent();
            this.Loaded += new RoutedEventHandler(ToolBarPanel_Loaded);
        }

        void ToolBarPanel_Loaded(object sender, RoutedEventArgs e)
        {
            this.CreateClickEvent();
        }

        public static DependencyProperty ToolBarItemsProperty = DependencyProperty.Register("ToolBarItems",
        typeof(PresentationFrameworkCollection<ToolBarItem>),
        typeof(ToolBarPanel),
        new PropertyMetadata(null));
        public UIElementCollection ToolBarItems
        {
            get 
            {
                return itemHolder.Children;
            }
        }

        public static DependencyProperty ToolBarItemsOrientation = DependencyProperty.Register("Orientation",
        typeof(Orientation),
        typeof(ToolBarPanel),
        new PropertyMetadata(null));
        public Orientation Orientation
        {
            get { return (itemHolder.Orientation); }
            set { itemHolder.Orientation=value; }
        }
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            itemHolder.DataContext = this;
        }

        private void CreateClickEvent()
        {
            foreach (UIElement elem in itemHolder.Children)
            {
                ToolBarItem item = elem as ToolBarItem;
                if(item!=null)
                    item.ToolBarItemClick += new Click(item_ToolBarItemClick);
            }
        }

        void item_ToolBarItemClick(object sender, string key)
        {
            if (ToolBarItemClick != null)
                this.ToolBarItemClick(sender, ((ToolBarItem)sender).ToolBarItemKey);
        }

    }
}

 

One property I wanted to highlight here is the ToolbarItems dependency property. This property exposes the StackPanels children property. Users can add Toolbar items through this property. At the end of this post, with a sample code I will explain the properties.

The delegate Click used in the ToolbarPanel is declared in ToolBarItem code.

ToolBar Item

This control creates the Toolbar button, it inherits from Button control. To make it similar to toolbar button I modified the Resource template of the button. Apart from the default properties of button a new property is added to provide the ability to add Image.

XAML

<Button x:Class="Controls.ToolBarItem"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">
    <Button.Resources>
        <ControlTemplate x:Key="BtnToolBarItemStyle" TargetType="Button">
            <Grid>
                <VisualStateManager.VisualStateGroups>
                    <VisualStateGroup x:Name="CommonStates">
                        <VisualState x:Name="Disabled"/>
                        <VisualState x:Name="Normal"/>
                        <VisualState x:Name="MouseOver">
                            <Storyboard>
                                <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="border" d:IsOptimized="True"/>
                                <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Margin)" Storyboard.TargetName="border">
                                    <DiscreteObjectKeyFrame KeyTime="0">
                                        <DiscreteObjectKeyFrame.Value>
                                            <Thickness>0</Thickness>
                                        </DiscreteObjectKeyFrame.Value>
                                    </DiscreteObjectKeyFrame>
                                </ObjectAnimationUsingKeyFrames>
                                <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Border.BorderThickness)" Storyboard.TargetName="border">
                                    <DiscreteObjectKeyFrame KeyTime="0">
                                        <DiscreteObjectKeyFrame.Value>
                                            <Thickness>1</Thickness>
                                        </DiscreteObjectKeyFrame.Value>
                                    </DiscreteObjectKeyFrame>
                                </ObjectAnimationUsingKeyFrames>
                                <ColorAnimation Duration="0" To="#FFF9B167" Storyboard.TargetProperty="(Border.Background).(GradientBrush.GradientStops)[1].(GradientStop.Color)" Storyboard.TargetName="border" d:IsOptimized="True"/>
                                <ColorAnimation Duration="0" To="#FFFFEFB6" Storyboard.TargetProperty="(Border.Background).(GradientBrush.GradientStops)[0].(GradientStop.Color)" Storyboard.TargetName="border" d:IsOptimized="True"/>
                                <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Border.CornerRadius)" Storyboard.TargetName="border">
                                    <DiscreteObjectKeyFrame KeyTime="0">
                                        <DiscreteObjectKeyFrame.Value>
                                            <CornerRadius>4</CornerRadius>
                                        </DiscreteObjectKeyFrame.Value>
                                    </DiscreteObjectKeyFrame>
                                </ObjectAnimationUsingKeyFrames>
                                <ColorAnimation Duration="0" To="#FFDEA158" Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" Storyboard.TargetName="border" d:IsOptimized="True"/>
                            </Storyboard>
                        </VisualState>
                        <VisualState x:Name="Pressed"/>
                    </VisualStateGroup>
                </VisualStateManager.VisualStateGroups>
                <Border x:Name="border" BorderBrush="Black" BorderThickness="1" Margin="1,2,2,1" Opacity="0">
                    <Border.Background>
                        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                            <GradientStop Color="Black" Offset="0"/>
                            <GradientStop Color="White" Offset="1"/>
                        </LinearGradientBrush>
                    </Border.Background>
                </Border>
                <StackPanel Orientation="Horizontal">
                    <Border x:Name="imgBorder"  BorderBrush="Black" BorderThickness="0" Margin="0" Width="16" Height="16">
                        <Border.Background>
                            <ImageBrush x:Name="imgBorderBrush" Stretch="Fill" ImageSource="{Binding ToolBarItemImage}"/>
                        </Border.Background>
                    </Border>
                    <TextBlock x:Name="caption" Grid.Column="1" TextWrapping="NoWrap" Text="{Binding Content}" FontSize="9.333" TextAlignment="Center" VerticalAlignment="Center" />
                </StackPanel>
            </Grid>
        </ControlTemplate>
    </Button.Resources>

    <Button.Template>
        <StaticResource ResourceKey="BtnToolBarItemStyle"/>
    </Button.Template>
    
</Button>

 

Code Behind

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections;
using System.ComponentModel;
namespace Controls
{
    public delegate void Click(object sender, string key);
    public partial class ToolBarItem : Button
    {
        public event Click ToolBarItemClick;
        public ToolBarItem()
        {
            InitializeComponent();
            this.Click += new RoutedEventHandler(ToolBarItem_Click);
        }

        void ToolBarItem_Click(object sender, RoutedEventArgs e)
        {
            if (ToolBarItemClick != null)
                this.ToolBarItemClick(sender, (string)GetValue(ToolBarItemKeyProperty));
        }

        public static DependencyProperty ToolBarItemImageProperty = DependencyProperty.Register("ToolBarItemImage",
        typeof(ImageSource),
        typeof(ToolBarItem),
        new PropertyMetadata(null));
        public ImageSource ToolBarItemImage
        {
            get { return (ImageSource)GetValue(ToolBarItemImageProperty); }
            set { SetValue(ToolBarItemImageProperty, value); }
        }

        public static DependencyProperty ToolBarItemKeyProperty = DependencyProperty.Register("ToolBarItemKey",
        typeof(String),
        typeof(ToolBarItem),
        new PropertyMetadata(null));
        public string ToolBarItemKey
        {
            get { return (string)GetValue(ToolBarItemKeyProperty); }
            set { SetValue(ToolBarItemKeyProperty, value); }
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            SetDataContext();
        }
        private void SetDataContext()
        {
            Border border = GetTemplateChild("imgBorder") as Border;
            border.DataContext = this;
            TextBlock txtCaption = GetTemplateChild("caption") as TextBlock;
            txtCaption.DataContext = this;

            if (this.Content == null)
            {
                txtCaption.Margin = new Thickness(0);
                border.Margin = new Thickness(3);
            }
            else
            {
                txtCaption.Margin = new Thickness(3);
            }
        }

    }
}
  • ToolBarItemImage: To set the source of the Image to display in the toolbar.

  • ToolBarItemKey: Provide a key to identify which button is clicked.

Test Page

The test page helps you to understand how we can use this new control

XAML

<controls:ChildWindow x:Class="Popups.TestToolBar"
           xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
           xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
           xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
           xmlns:tlBar="clr-namespace:EmblemDesigner.Controls" Title="TestToolBar" mc:Ignorable="d" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" d:DesignHeight="265" d:DesignWidth="432">
    <Grid x:Name="LayoutRoot" Margin="2">
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        
        <tlBar:ToolBarPanel Height="50" Background="Transparent" Orientation="Horizontal" ToolBarItemClick="ToolBarPanelExt_ToolBarItemClick" >
            <tlBar:ToolBarPanel.ToolBarItems>
                <tlBar:ToolBarItem Margin="5" ToolBarItemImage="/Ico_Arrow.png"  Content="Arrow" ToolBarItemKey="Arrow"></tlBar:ToolBarItem>
                <tlBar:ToolBarItem Margin="5" ToolBarItemImage="/Ico_Circle.png"   ToolBarItemKey="Circle"></tlBar:ToolBarItem>
            </tlBar:ToolBarPanel.ToolBarItems>
        </tlBar:ToolBarPanel>
        
        <Button x:Name="CancelButton"  Content="Cancel" Click="CancelButton_Click" Width="75" Height="23" HorizontalAlignment="Right" Margin="0,12,0,0" Grid.Row="1" />
        <Button x:Name="OKButton"  Content="OK" Click="OKButton_Click" Width="75" Height="23" HorizontalAlignment="Right" Margin="0,12,79,0" Grid.Row="1" />
    </Grid>
</controls:ChildWindow>

 

Code Behind

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace Popups
{
    public partial class TestToolBar : ChildWindow
    {
        public TestToolBar()
        {
            InitializeComponent();
        }

        private void OKButton_Click(object sender, RoutedEventArgs e)
        {
            this.DialogResult = true;
        }

        private void CancelButton_Click(object sender, RoutedEventArgs e)
        {
            this.DialogResult = false;
        }


        private void ToolBarPanel_ToolBarItemClick(object sender, string key)
        {
            switch (key)
            {
                case "circle":
                    break;
                case "arrow":
                    break;
            }
        }
    }
}
 

If we attach ToolBarItemClick event to ToolBar panel, it will generate an even handler as shown above in italics. The event will provide you a key and the sender. The key provides the value we set for ToolBarItemKey of the ToolBarItem control. Based on the key we can take different actions. As ToolbarItem is inherited from button you can use the default click event provided by Button control.

Written by Sony Arouje

August 25, 2010 at 4:26 pm

Posted in Silverlight

Tagged with ,

Oval TextBox

leave a comment »

My project require an oval text box. First place I started to make my changes is in the default template of Textbox. The default template of any control can be retrieved through expression blend (Right click on the Control and select Edit Template/Edit a Copy).

Below is the default template of TextBox control

    <UserControl.Resources>
        <ControlTemplate x:Key="ValidationToolTipTemplate">
            <Grid x:Name="Root" Margin="5,0" Opacity="0" RenderTransformOrigin="0,0">
                <Grid.RenderTransform>
                    <TranslateTransform x:Name="xform" X="-25"/>
                </Grid.RenderTransform>
                <VisualStateManager.VisualStateGroups>
                    <VisualStateGroup x:Name="OpenStates">
                        <VisualStateGroup.Transitions>
                            <VisualTransition GeneratedDuration="0"/>
                            <VisualTransition GeneratedDuration="0:0:0.2" To="Open">
                                <Storyboard>
                                    <DoubleAnimation Duration="0:0:0.2" To="0" Storyboard.TargetProperty="X" Storyboard.TargetName="xform">
                                        <DoubleAnimation.EasingFunction>
                                            <BackEase Amplitude=".3" EasingMode="EaseOut"/>
                                        </DoubleAnimation.EasingFunction>
                                    </DoubleAnimation>
                                    <DoubleAnimation Duration="0:0:0.2" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="Root"/>
                                </Storyboard>
                            </VisualTransition>
                        </VisualStateGroup.Transitions>
                        <VisualState x:Name="Closed">
                            <Storyboard>
                                <DoubleAnimation Duration="0" To="0" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="Root"/>
                            </Storyboard>
                        </VisualState>
                        <VisualState x:Name="Open">
                            <Storyboard>
                                <DoubleAnimation Duration="0" To="0" Storyboard.TargetProperty="X" Storyboard.TargetName="xform"/>
                                <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="Root"/>
                            </Storyboard>
                        </VisualState>
                    </VisualStateGroup>
                </VisualStateManager.VisualStateGroups>
                <Border Background="#052A2E31" CornerRadius="5" Margin="4,4,-4,-4"/>
                <Border Background="#152A2E31" CornerRadius="4" Margin="3,3,-3,-3"/>
                <Border Background="#252A2E31" CornerRadius="3" Margin="2,2,-2,-2"/>
                <Border Background="#352A2E31" CornerRadius="2" Margin="1,1,-1,-1"/>
                <Border Background="#FFDC000C" CornerRadius="2"/>
                <Border CornerRadius="2">
                    <TextBlock Foreground="White" MaxWidth="250" Margin="8,4,8,4" TextWrapping="Wrap" Text="{Binding (Validation.Errors)[0].ErrorContent}" UseLayoutRounding="false"/>
                </Border>
            </Grid>
        </ControlTemplate>
        <Style x:Key="OvalTextBoxStyle" TargetType="TextBox">
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="Background" Value="#FFFFFFFF"/>
            <Setter Property="Foreground" Value="#FF000000"/>
            <Setter Property="Padding" Value="2"/>
            <Setter Property="BorderBrush">
                <Setter.Value>
                    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                        <GradientStop Color="#FFA3AEB9" Offset="0"/>
                        <GradientStop Color="#FF8399A9" Offset="0.375"/>
                        <GradientStop Color="#FF718597" Offset="0.375"/>
                        <GradientStop Color="#FF617584" Offset="1"/>
                    </LinearGradientBrush>
                </Setter.Value>
            </Setter>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="TextBox">
                        <Grid x:Name="RootElement">
                            <VisualStateManager.VisualStateGroups>
                                <VisualStateGroup x:Name="CommonStates">
                                    <VisualState x:Name="Normal"/>
                                    <VisualState x:Name="MouseOver">
                                        <Storyboard>
                                            <ColorAnimation Duration="0" To="#FF99C1E2" Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" Storyboard.TargetName="MouseOverBorder"/>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="Disabled">
                                        <Storyboard>
                                            <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="DisabledVisualElement"/>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="ReadOnly">
                                        <Storyboard>
                                            <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="ReadOnlyVisualElement"/>
                                        </Storyboard>
                                    </VisualState>
                                </VisualStateGroup>
                                <VisualStateGroup x:Name="FocusStates">
                                    <VisualState x:Name="Focused">
                                        <Storyboard>
                                            <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="FocusVisualElement"/>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="Unfocused">
                                        <Storyboard>
                                            <DoubleAnimation Duration="0" To="0" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="FocusVisualElement"/>
                                        </Storyboard>
                                    </VisualState>
                                </VisualStateGroup>
                                <VisualStateGroup x:Name="ValidationStates">
                                    <VisualState x:Name="Valid"/>
                                    <VisualState x:Name="InvalidUnfocused">
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="ValidationErrorElement">
                                                <DiscreteObjectKeyFrame KeyTime="0">
                                                    <DiscreteObjectKeyFrame.Value>
                                                        <Visibility>Visible</Visibility>
                                                    </DiscreteObjectKeyFrame.Value>
                                                </DiscreteObjectKeyFrame>
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="InvalidFocused">
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="ValidationErrorElement">
                                                <DiscreteObjectKeyFrame KeyTime="0">
                                                    <DiscreteObjectKeyFrame.Value>
                                                        <Visibility>Visible</Visibility>
                                                    </DiscreteObjectKeyFrame.Value>
                                                </DiscreteObjectKeyFrame>
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="IsOpen" Storyboard.TargetName="validationTooltip">
                                                <DiscreteObjectKeyFrame KeyTime="0">
                                                    <DiscreteObjectKeyFrame.Value>
                                                        <System:Boolean>True</System:Boolean>
                                                    </DiscreteObjectKeyFrame.Value>
                                                </DiscreteObjectKeyFrame>
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                </VisualStateGroup>
                            </VisualStateManager.VisualStateGroups>
                            <Border x:Name="Border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}"  Opacity="1" CornerRadius="20">
                                <Grid>
                                    <Border x:Name="ReadOnlyVisualElement" Background="#5EC9C9C9" Opacity="0" CornerRadius="20"/>
                                    <Border x:Name="MouseOverBorder" BorderBrush="Transparent" BorderThickness="1" CornerRadius="20">
                                        <ScrollViewer x:Name="ContentElement" BorderThickness="0" IsTabStop="False" Padding="{TemplateBinding Padding}"/>
                                    </Border>
                                </Grid>
                            </Border>
                            <Border x:Name="DisabledVisualElement" BorderBrush="#A5F7F7F7" BorderThickness="{TemplateBinding BorderThickness}" Background="#A5F7F7F7" IsHitTestVisible="False" Opacity="0" CornerRadius="20"/>
                            <Border x:Name="FocusVisualElement" BorderBrush="#FF6DBDD1" BorderThickness="{TemplateBinding BorderThickness}" IsHitTestVisible="False" Margin="1" Opacity="0" CornerRadius="20"/>
                            <Border x:Name="ValidationErrorElement" BorderBrush="#FFDB000C" BorderThickness="1"  Visibility="Collapsed" CornerRadius="20">
                                <ToolTipService.ToolTip>
                                    <ToolTip x:Name="validationTooltip" DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}" Placement="Right" PlacementTarget="{Binding RelativeSource={RelativeSource TemplatedParent}}" Template="{StaticResource ValidationToolTipTemplate}">
                                        <ToolTip.Triggers>
                                            <EventTrigger RoutedEvent="Canvas.Loaded">
                                                <BeginStoryboard>
                                                    <Storyboard>
                                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="IsHitTestVisible" Storyboard.TargetName="validationTooltip">
                                                            <DiscreteObjectKeyFrame KeyTime="0">
                                                                <DiscreteObjectKeyFrame.Value>
                                                                    <System:Boolean>true</System:Boolean>
                                                                </DiscreteObjectKeyFrame.Value>
                                                            </DiscreteObjectKeyFrame>
                                                        </ObjectAnimationUsingKeyFrames>
                                                    </Storyboard>
                                                </BeginStoryboard>
                                            </EventTrigger>
                                        </ToolTip.Triggers>
                                    </ToolTip>
                                </ToolTipService.ToolTip>
                                <Grid Background="Transparent" HorizontalAlignment="Right" Height="12" Margin="1,-4,-4,0" VerticalAlignment="Top" Width="12">
                                    <Path Data="M 1,0 L6,0 A 2,2 90 0 1 8,2 L8,7 z" Fill="#FFDC000C" Margin="1,3,0,0"/>
                                    <Path Data="M 0,0 L2,0 L 8,6 L8,8" Fill="#ffffff" Margin="1,3,0,0"/>
                                </Grid>
                            </Border>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </UserControl.Resources>

To make my TextBox oval I wanted to add/edit the CornerRadius property to some of the Border controls in the above Template. Below are the Borders we need to visit.

Border
DisabledVisualElement
FocusVisualElement
ReadOnlyVisualElement
MouseOverBorder

Add/Modify CornerRadius property to the above Borders and set it to what ever the value you need.

But the hurdle here is to change the CornerRadius, every time we need to set a different value to all the Border control I mentioned above. To make my life easier I created a new TextBox user control with CornerRadius property.

 TextBox with CornerRadius property

Create a new UserControl and inherit from TextBox as shown below

<TextBox x:Class=”SonyControls.Controls.OvalTextBox”
  
xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation&#8221;
  
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml&#8221;
  
xmlns:d=”http://schemas.microsoft.com/expression/blend/2008&#8243;
  
xmlns:mc=”http://schemas.openxmlformats.org/markup-compatibility/2006&#8243;
  
xmlns:System=”clr-namespace:System;assembly=mscorlib”
  
mc:Ignorable=”d”
  
d:DesignHeight=”300″d:DesignWidth=”400″>

    <TextBox.Resources>
                 I am not adding the entire template here. Its already depicted above.

….

…..

….

         <Border x:Name=”Border” BorderBrush=”{TemplateBinding BorderBrush}” BorderThickness=”{TemplateBinding BorderThickness}”

         Background=”{TemplateBinding Background}” Opacity=”1″ CornerRadius={Binding CornerRadius}>

      </TextBox.Resources>

               <TextBox.Style>

                         <StaticResource ResourceKey=”OvalTextBoxStyle”/>

             </TextBox.Style

</TextBox>

Modify the CornerRadius value with “{Binding CornerRadius}” as shown above.

In the code behind of my user control I added a dependency property and some code as shown below.

public partial class OvalTextBox : TextBox { public OvalTextBox() { InitializeComponent(); } public static DependencyProperty CornerRadiusProperty = DependencyProperty.Register("CornerRadius", typeof(CornerRadius), typeof(OvalTextBox), new PropertyMetadata(null)); public CornerRadius CornerRadius { get { return (CornerRadius)GetValue(CornerRadiusProperty); } set { SetValue(CornerRadiusProperty, value); } } public override void OnApplyTemplate() { base.OnApplyTemplate(); SetDataContext();

    }

private void SetDataContext()

{

string[] bordersToUpdate = { "Border", "DisabledVisualElement", "FocusVisualElement","ReadOnlyVisualElement", "MouseOverBorder", "WatermarkVisualElement" };

foreach (string str in bordersToUpdate)

{

Border border = GetTemplateChild(str) as Border;

if (border != null)

{ border.DataContext = this; }

}

}

}

 

That’s it we are done with a new Textbox with CornerRadius property, you can access the new property from Code behind or through XAML.

Written by Sony Arouje

August 25, 2010 at 4:25 pm

Posted in Silverlight

Silverlight UserControl Inheritance

leave a comment »

My current project requires several silverlight user controls. Most of the control has some common functionalities. I decided to create a base class inherits from UserControl. Then add the base class to my user controls.

The issue arise when I tried to build the solution, I started getting the bellow compile time error.

Error    1    Partial declarations of ‘ImageEditor.Controls.CallOut’ must not specify different base classes    F:\XXXX\obj\Debug\Controls\CallOut.g.i.cs    36    26    <ProjectName>

The solution to this issue is, in XAML change <UserControl …..</UserControl> to the name of your base class. See the eg. below

<UI:ControlBase x:Class="ImageEditor.Controls.CallOut"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:UI="clr-namespace:ImageEditor.Controls"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">    
    <Grid x:Name="LayoutRoot" Background="White">
        <Border  x:Name="rectBorder" Grid.Row="0" BorderBrush="Black" BorderThickness="3" CornerRadius="5">
            <TextBox x:Name="txtAnnotate" AcceptsReturn="True"></TextBox>
        </Border>
    </Grid>
</UI:ControlBase >

In the above xaml I replace UserControl with my base class. In order to use my base class I should refer my namespace using xmlns:UI=”clr-…..”. You can see the changes by looking at the sections underlined.

Written by Sony Arouje

August 25, 2010 at 4:24 pm

Posted in Silverlight

%d bloggers like this: