Silverlight for Windows Phone 7: Change panorama control’s title

June 29th, 2011 No comments

     You can easily change the look of Panorama-control title by applying TitleTemplate:

<controls:Panorama Title="my pano">
    <controls:Panorama.TitleTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding}" FontSize="100" Margin="0,50,0,0" />
        </DataTemplate>
    </controls:Panorama.TitleTemplate>
</controls:Panorama>

This piece of xaml allows to get the title smaller.

Panorama Title before

Before

After

Pay attention to Margin-attribute stated above. The default attributes for Panorama title is

Margin="10,-76,0,9"
FontSize="187"
HorizontalAlignment="Left"

and if you decrease the font size without correction of top-margin, your title can be hidden or clipped by upper bound of the screen.

If you want to add image to the title, use the next sample as the base:

<controls:Panorama.TitleTemplate>
    <DataTemplate>
        <StackPanel Orientation="Horizontal">
            <Image x:Name="logoImage" Margin="0,80,0,0" Source="/ApplicationIcon.png" />
            <TextBlock Text="{Binding}" FontSize="100" Margin="0,50,0,0" />
        </StackPanel>
    </DataTemplate>
</controls:Panorama.TitleTemplate>
Panorama Image TitleTemplate

Image in title

Related posts:

Silverlight for Windows Phone 7: How to bind UserControl to itself (сontinuation)

June 20th, 2011 No comments

     In one of my previous posts (How to bind UserControl to itself) I showed an implementation of BoundToSelfControl. It’s time to supplement this implementation with a new ability.

Obviously, if data, that should be rendered, is changed, we need to refresh our page in order that the actual values would be displayed. In other words, if at least one property of the object preserved in _source is changed, we have to be notified somehow about this fact and to refresh the displayed values. A standard approach is an usage of INotifyPropertyChanged, it’s precisely what is used by a standard binding system. Let’s do the same.

First of all, we need to subscribe to PropertyChanged event of our data source object, of course, if the one supports INotifyPropertyChanged. BoundToSelfControl‘s OnLoad method will look like

protected virtual void OnLoad()
{
    if (_source == null)
    {
        _source = DataContext;
        DataContext = this;
                
        INotifyPropertyChanged iNotifyPropertyChanged = _source as INotifyPropertyChanged;
        if (iNotifyPropertyChanged != null) // check if _source supports INotifyPropertyChanged;
            iNotifyPropertyChanged.PropertyChanged += new PropertyChangedEventHandler(iNotifyPropertyChanged_PropertyChanged); // subscribing to source property changes
    }
}

protected virtual void iNotifyPropertyChanged_PropertyChanged(object sender, PropertyChangedEventArgs e)
{    
}

Secondly, BoundToSelfControl has to implement INotifyPropertyChanged as well in order to let the standard binding system know that it has to retake values of BoundToSelfControl‘s properties.

public class BoundToSelfControl : UserControl, INotifyPropertyChanged
{ 
    public event PropertyChangedEventHandler PropertyChanged;

    // ... the rest of code

    // Raises the PropertyChanged event, passing the source property that is being updated
    protected void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

Thirdly, in iNotifyPropertyChanged_PropertyChanged of a derived control we need to analyse what property of data source object is changed and then to fire PropertyChanged event with the name of appropriate property, for example, if ‘Price’ property of Product-object is changed, we fire PropertyChanged event with the ‘ProductPrice’ (Product class represents data to render).

public partial class ProductDispalyControl : BoundToSelfControl
{
    // ... the rest of code

    protected override void iNotifyPropertyChanged_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if ("price".Equals(e.PropertyName, StringComparison.OrdinalIgnoreCase))
            NotifyPropertyChanged("ProductPrice");
        else
            if ("name".Equals(e.PropertyName, StringComparison.OrdinalIgnoreCase))
                NotifyPropertyChanged("ProductName");
    }
}

And the improved final version of BoundToSelfControl and ProductDispalyControl:

public class BoundToSelfControl : UserControl, INotifyPropertyChanged
{
    protected object _source = null;

    public event PropertyChangedEventHandler PropertyChanged;

    public BoundToSelfControl() : base()
    {
        Loaded += new RoutedEventHandler(BoundToSelfControl_Loaded);
    }

    protected virtual void OnLoad()
    {
        // NOTE: When we navigate from the current PhoneApplicationPage,
        // the state of the page is persisted (including the states of controls the page contains).
        // It's so called Tombstoning. If we get back to the persisted page,
        // BoundToSelfControl's Loaded-handler is called again (as opposed to the control constructor).
        // When it happens, DataContext already refers to the control itself, and there is no need to do anything else.
        // Of course, it's topical for windows phone 7 only
        if (_source == null)
        {
            _source = DataContext; // save data passed through DataContext in the field _source
            DataContext = this;    // bind to itself

            INotifyPropertyChanged iNotifyPropertyChanged = _source as INotifyPropertyChanged;
            if (iNotifyPropertyChanged != null) // check if _source supports INotifyPropertyChanged;
                iNotifyPropertyChanged.PropertyChanged += new PropertyChangedEventHandler(iNotifyPropertyChanged_PropertyChanged); // subscribing to source property changes
        }
    }

    protected virtual void OnDataSourcePropertyChanged(string propertyName)
    {
    }

    // Raises the PropertyChanged event, passing the source property that is being updated
    protected void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    void iNotifyPropertyChanged_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        OnDataSourcePropertyChanged(e.PropertyName);
    }    

    void BoundToSelfControl_Loaded(object sender, RoutedEventArgs e)
    {
        OnLoad();
    }
}

public class Product
{
    public string Name  { get; set; }
    public double Price { get; set; }
}

public partial class ProductDispalyControl : BoundToSelfControl
{
    protected Product _product = null;

    public Product CurrentProduct
    {
        get
        {
            if (_product == null)
                _product = (Product)_source;
            return _product;
        }
    }

    public string ProductName
    {
        get { return string.Format("<{0}>", CurrentProduct.Name); }
    }

    public string ProductPrice
    {
        get { return string.Format("${0}", CurrentProduct.Price); }
    }

    public ProductDispalyControl()
    {
        InitializeComponent();
    }

    protected override void OnDataSourcePropertyChanged(string propertyName)
    {
        if ("price".Equals(propertyName, StringComparison.OrdinalIgnoreCase))
            NotifyPropertyChanged("ProductPrice");
        else
            if ("name".Equals(propertyName, StringComparison.OrdinalIgnoreCase))
                NotifyPropertyChanged("ProductName");
    }    
}
Related posts:

Silverlight for Windows Phone 7: How to get color from hex string

June 9th, 2011 No comments

     In my Silverlight Windows Phone 7 application I actively use HTML color codes, that are hexadecimal strings representing components of red, green and blue colors. Additionally, such hex-string can contains alpha channel value. For example, #FF0080 (Light Purple). To convert hex-strings to Color I have developed the following method:

protected static Color GetColorFromHexString(string s)
{ 
    // remove artifacts
    s = s.Trim().TrimStart('#');

    // only 8 (with alpha channel) or 6 symbols are allowed
    if(s.Length != 8 && s.Length != 6)
        throw new ArgumentException("Unknown string format!");

    int  startParseIndex    = 0;
    bool alphaChannelExists = s.Length == 8; // check if alpha canal exists            

    // read alpha channel value
    byte a = 255;
    if(alphaChannelExists)
    {
        a = System.Convert.ToByte(s.Substring(0, 2), 16);
        startParseIndex += 2;
    }

    // read r value
    byte r = System.Convert.ToByte(s.Substring(startParseIndex, 2), 16);
    startParseIndex += 2;
    // read g value
    byte g = System.Convert.ToByte(s.Substring(startParseIndex, 2), 16);
    startParseIndex += 2;
    // read b value
    byte b = System.Convert.ToByte(s.Substring(startParseIndex, 2), 16);

    return Color.FromArgb(a, r, g, b);
}

I Hope this helps someone!

Related posts:

Silverlight for Windows Phone 7: How to bind UserControl to itself

June 8th, 2011 No comments

     Very often I want my UserControl to be bound to itself. It allows to have more control under data presentation and formatting. To bind the UserControl to itself declaratively we need to add DataContext initialization to the xaml-file:

<UserControl x:Class="SomeNamespace.ProductDispalyControl"
    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"
    d:DesignHeight="480" d:DesignWidth="480"
    DataContext = "{Binding RelativeSource={RelativeSource Self}}">

    <StackPanel x:Name="LayoutRoot">
        <TextBlock Text="{Binding ProductName}" />
        <TextBlock Text="{Binding ProductPrice}" />                
    </StackPanel>

</UserControl>

This works great, if we provide the UserControl with an ability to receive somehow data, which should be rendered. Let’s take a look at example:

/// <summary>
/// Represents data to render
/// </summary>
public class Product
{
    public string Name  { get; set; }
    public double Price { get; set; }
}

/// <summary>
/// Renders information about product
/// </summary>
public partial class ProductDispalyControl : UserControl
{
    protected Product _product = null;

    public Product CurrentProduct
    {
        get { return _product; }
        set { _product = value; }
    }

    public string ProductName
    {
        get { return string.Format("<{0}>", CurrentProduct.Name); }
    }

    public string ProductPrice
    {
        get { return string.Format("${0}", CurrentProduct.Price); }
    }

    public ProductDispalyControl(Product product)
    {
        _product = product;
        InitializeComponent();            
    }
    public ProductDispalyControl()
    {        
        InitializeComponent();
    }        
}

Product (data to render) can be passed into the UserControl through the constructor, if the control is created dynamically, for example,

public ParentControl()
    {        
        InitializeComponent();

        ProductDispalyControl productCtrl = new ProductDispalyControl(product); // passing data through the constructor
        placeHolder.Children.Add(productCtrl);
    }

or can be set through the property CurrentProduct inside the constructor of parent-control right after the UserControl is created, if the control is declared in xaml-file of parent control

public ParentControl()
{        
    InitializeComponent();
    productCtrl.CurrentProduct = Product; // passing data through the property
}

If you are devoted to declarative way, it’s not convenient every time to add some additional initialization code in code-behind. But in the same time we can’t bind DataContext property of our UserControl to the data in xaml-file, because we need the UserControl to be bound to itself. Of course, you still can try binding CurrentProduct to the data. For this you need to transform CurrentProduct property to DependencyProperty to support binding. However, in some cases it doesn’t help, for example,

<ItemsControl ItemsSource="{Binding Path=ProductCollection}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
      	    <someNamespacePrefix:ProductDispalyControl />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

In this case every Product from ProductCollection will be passed to the certain ProductDispalyControl through DataContext property by default, however it conflicts with our main idea to have the UserControl bound to itself. To overcome this problem I’ve developed a simple class

namespace MyControls
{
    public class BoundToSelfControl : UserControl
    {
        protected object _source = null;

        public BoundToSelfControl() : base()
        {
            Loaded += new RoutedEventHandler(BoundToSelfControl_Loaded);            
        }

        public virtual void OnLoad()
        {
            // NOTE: When we navigate from the current PhoneApplicationPage, 
            // the state of the page is persisted (including the states of controls the page contains). 
            // It's so called Tombstoning. If we get back to the persisted page, 
            // BoundToSelfControl's Loaded-handler is called again (as opposed to the control constructor). 
            // When it happens, DataContext already refers to the control itself, and there is no need to do anything else.
            // Of course, it's topical for windows phone 7 only
            if (_source == null)
            {
                _source = DataContext; // save data passed through DataContext in the field _source
                DataContext = this;    // bind to itself
            }
        }

        void BoundToSelfControl_Loaded(object sender, RoutedEventArgs e)
        {
            OnLoad();
        }
    }
}

In a Loaded-handler BoundToSelfControl gets Product passed through DataContext and saves it in the field _source, then binds itself to itself. Now we need to derive ProductDispalyControl from BoundToSelfControl:

public partial class ProductDispalyControl : BoundToSelfControl
{
    protected Product _product = null;

    public Product CurrentProduct
    {
        get 
        {
            if (_product == null)
                _product = (Product)_source;
            return _product; 
        }            
    }

    public string ProductName
    {
        get { return string.Format("<{0}>", CurrentProduct.Name); }
    }

    public string ProductPrice
    {
        get { return string.Format("${0}", CurrentProduct.Price); }
    }

    public ProductDispalyControl()
    {
        InitializeComponent();
    }
}

The xaml-file of ProductDispalyControl will be the following:

<myControls:BoundToSelfControl x:Class="SomeNamespace.ProductDispalyControl"
    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:myControls="clr-namespace:MyControls"
    d:DesignHeight="480" d:DesignWidth="480"
    DataContext = "{Binding RelativeSource={RelativeSource Self}}">

    <StackPanel x:Name="LayoutRoot">
        <TextBlock Text="{Binding ProductName}" />
        <TextBlock Text="{Binding ProductPrice}" />                
    </StackPanel>

</myControls:BoundToSelfControl>

Do not forget to add xmlns:myControls=”clr-namespace:MyControls” to declaration. After this an auto generated part of ProductDispalyControl will be successfully created as well.

I use BoundToSelfControl every time when I create a new UserControl. I hope it will be useful for someone else.

ps I utilize BoundToSelfControl in an Silverlight Windows Phone 7 application, but I think it will work with usual Silverlight with no problems.

See Continuation of the topic

Related posts:

WinForms: How to hide checkbox of the certain TreeNode in TreeView control

May 18th, 2011 4 comments

     Recently I needed to hide the checkboxes of some nodes in a TreeView-control, i.e. some nodes should be checkable, but the rest shouldn’t.

The standard TreeView doesn’t allow doing that directly, but Windows API will help us out. The main idea is to catch the moment when a node has been added to the TreeView, then to examine whether the node’s checkbox must be hidden and, if yes, to send a certain TVM_SETITEM message to the TreeView to hide the checkbox.

Unfortunately, the TreeView doesn’t provide us with an event to be fired right after a node has been added. So, we don’t have any choice, but to deal with WinAPI messages directly inside WndProc.

Having used .Net Reflector I’ve found out that while a node is being added to the Nodes-collection of either the TreeView or another node the following code is running (this piece of code is borrowed from the internal Realize method of the TreeNode class):

this.handle = UnsafeNativeMethods.SendMessage(
      new HandleRef(this.TreeView, this.TreeView.Handle), 
      NativeMethods.TVM_INSERTITEM, 0, ref lParam); // the first statement
treeView.nodeTable[this.handle] = this; // the second statement
this.UpdateNode(4); // the third statement

As we can see, after the first statement has been executed the TreeView receives a TVM_INSERTITEM message. In the WndProc of the TreeView, we could catch this message and fetch out the newly added node’s handle from it. The next step would be a getting a TreeNode-object corresponding to the handle as we need the latter to examine whether its checkbox must be hidden. However, at that stage the handle and the TreeNode wrapping it couldn’t yet be matched. The correct matching is available only after the pair <node’s handle, TreeNode-object> has been added to the TreeView‘s hashtable named nodeTable, in other words, after the second statement has completed. Evidently, the TVM_INSERTITEM message would be already processed by that moment. That means the TVM_INSERTITEM can’t be used, and we have to catch and handle another WinAPI message.

Luckily, right after the node has been added and the mapping between the handle and the TreeNode-object has been set up, the UpdateNode method (the third statement) emits a TVM_SETITEM message to the TreeView. So, I decided to handle this type of messages to hide unwanted checkboxes.

Below are two classes, HiddenCheckBoxTreeNode and MixedCheckBoxesTreeView, derived from the built-in TreeNode and TreeView classes respectively. The HiddenCheckBoxTreeNode class indicates a node with checkbox to be hidden. The MixedCheckBoxesTreeView class, in turn, hides unwanted checkboxes.

/// <summary>
/// Represents a node with hidden checkbox
/// </summary>
public class HiddenCheckBoxTreeNode : TreeNode
{
    public HiddenCheckBoxTreeNode() { }
    public HiddenCheckBoxTreeNode(string text) : base(text) { }
    public HiddenCheckBoxTreeNode(string text, TreeNode[] children) : base(text, children) { }
    public HiddenCheckBoxTreeNode(string text, int imageIndex, int selectedImageIndex) : base(text, imageIndex, selectedImageIndex) { }
    public HiddenCheckBoxTreeNode(string text, int imageIndex, int selectedImageIndex, TreeNode[] children) : base(text, imageIndex, selectedImageIndex, children) { }
    protected HiddenCheckBoxTreeNode(SerializationInfo serializationInfo, StreamingContext context) : base(serializationInfo, context) { }
}

public class MixedCheckBoxesTreeView : TreeView
{
    /// <summary>
    /// Specifies the attributes of a node
    /// </summary>
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    public struct TV_ITEM
    {
        public int    Mask;
        public IntPtr ItemHandle;
        public int    State;
        public int    StateMask;
        public IntPtr TextPtr;
        public int    TextMax;
        public int    Image;
        public int    SelectedImage;
        public int    Children;
        public IntPtr LParam;
    }
 
    public const int TVIF_STATE          = 0x8;
    public const int TVIS_STATEIMAGEMASK = 0xF000;
 
    public const int TVM_SETITEMA = 0x110d;
    public const int TVM_SETITEM  = 0x110d;
    public const int TVM_SETITEMW = 0x113f;

    public const int TVM_GETITEM  = 0x110C;
 
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr SendMessage(HandleRef hWnd, int msg, int wParam, ref TV_ITEM lParam);
 
    protected override void WndProc(ref Message m)
    {
        base.WndProc(ref m);
 
        // trap TVM_SETITEM message
        if (m.Msg == TVM_SETITEM || m.Msg == TVM_SETITEMA || m.Msg == TVM_SETITEMW)
            // check if CheckBoxes are turned on
            if (CheckBoxes)
            {
                // get information about the node
                TV_ITEM tv_item = (TV_ITEM)m.GetLParam(typeof(TV_ITEM));
                HideCheckBox(tv_item);
            }
    }   
 
    protected void HideCheckBox(TV_ITEM tv_item)
    {
        if (tv_item.ItemHandle != IntPtr.Zero)
        {
            // get TreeNode-object, that corresponds to TV_ITEM-object
            TreeNode currentTN = TreeNode.FromHandle(this, tv_item.ItemHandle);
 
            HiddenCheckBoxTreeNode hiddenCheckBoxTreeNode = currentTN as HiddenCheckBoxTreeNode;
            // check if it's HiddenCheckBoxTreeNode and
            // if its checkbox already has been hidden

            if(hiddenCheckBoxTreeNode != null)
            {
                HandleRef treeHandleRef = new HandleRef(this, Handle);

                // check if checkbox already has been hidden
                TV_ITEM currentTvItem    = new TV_ITEM();
                currentTvItem.ItemHandle = tv_item.ItemHandle;
                currentTvItem.StateMask  = TVIS_STATEIMAGEMASK;
                currentTvItem.State      = 0;

                IntPtr res = SendMessage(treeHandleRef, TVM_GETITEM, 0, ref currentTvItem);
                bool needToHide = res.ToInt32() > 0 && currentTvItem.State != 0;

                if (needToHide)
                {
                    // specify attributes to update
                    TV_ITEM updatedTvItem    = new TV_ITEM();
                    updatedTvItem.ItemHandle = tv_item.ItemHandle;
                    updatedTvItem.Mask       = TVIF_STATE;
                    updatedTvItem.StateMask  = TVIS_STATEIMAGEMASK;
                    updatedTvItem.State      = 0;
 
                    // send TVM_SETITEM message
                    SendMessage(treeHandleRef, TVM_SETITEM, 0, ref updatedTvItem);
                }
            }
        }
    }
 
    protected override void OnBeforeCheck(TreeViewCancelEventArgs e)
    {
        base.OnBeforeCheck(e);
 
        // prevent checking/unchecking of HiddenCheckBoxTreeNode,
        // otherwise, we will have to repeat checkbox hiding
        if (e.Node is HiddenCheckBoxTreeNode)
            e.Cancel = true;
    }
}

Note the OnBeforeCheck method is intended to prohibit a TreeNode‘s Checked property changing, otherwise we would have to hide an appropriate checkbox again.

Below is a sample of using. Put a MixedCheckBoxesTreeView control upon a form and set a Load handler to the method listed below.

private void Form1_Load(object sender, EventArgs e)
{
    mixedCheckBoxesTreeView1.CheckBoxes = true;
    mixedCheckBoxesTreeView1.Nodes.Clear();

    HiddenCheckBoxTreeNode tn = new HiddenCheckBoxTreeNode("Root Node 1");
    mixedCheckBoxesTreeView1.Nodes.Add(tn);

    TreeNode tn2 = new TreeNode("Child Node Z");
    tn.Nodes.Add(tn2);

    HiddenCheckBoxTreeNode tn3 = new HiddenCheckBoxTreeNode("Child Node A");
    tn3.Checked = true; // just to test that nothing happens here
    tn.Nodes.Add(tn3);

    HiddenCheckBoxTreeNode tn4 = new HiddenCheckBoxTreeNode("Child Node X");
    tn.Nodes.Add(tn4);

    TreeNode tn5 = new TreeNode("Child Node D");
    tn.Nodes.Add(tn5);

    TreeNode tn6 = new TreeNode("Root Node 2");
    mixedCheckBoxesTreeView1.Nodes.Add(tn6);

    TreeNode tn7 = new TreeNode("Root Node 3");
    mixedCheckBoxesTreeView1.Nodes.Add(tn7);

    HiddenCheckBoxTreeNode tn8 = new HiddenCheckBoxTreeNode("Child Node A");
    tn7.Nodes.Add(tn8);

    mixedCheckBoxesTreeView1.ExpandAll();
}

To play with the approach implementation, download a Visual Studio 2010 solution from here.

Related posts: