Log in to like this post! How to Create XAML WinRT Components for Windows 8 Metro Applications [Infragistics] Mihail Mateev / Friday, March 23, 2012 Metro applications have an innovative new interface and a component-based architecture. Many developers created components for XAML-related technologies like Silverlight / WPF and developers of jQuery components they would like to create WinRT controls for Windows Metro applications.One of the new challenges for developers is to work on Windows 8 Metro applications. This article is about how to start creating XAML WinRT components.You will You will learn how to create a simple XAML control, using C# and how to use it in a demo Metro application. Developers will be excited from the significant improvements in Windows 8 Consumer Preview and Visual Studio 11 Beta, related to Metro applications development. In September 2011 Microsoft announced Windows 8 Developer Preview and Visual Studio 2011 Developer Preview. There was some missing features in the Developer Preview: Visual Studio Developer Preview 11 had no templates for custom controls ObservableCollection<T> didn’t support INotifyCollectionChanged (developers must create custom collections, that implement IObservableVector<T> XAML Dependency Properties had a different syntax from the Silverlight / WPF implementation In Visual Studio 11 Developer Preview developers should set Generic.xaml build type as Content (in Silverlight it is Page) XAML Metro components had some issues in design mode and often it was not possible programmers to see the UI at design time. Dependency Property definition 1: // Using a DependencyProperty as the backing store for Value. 2: //This enables animation, styling, binding, etc... 3: public static readonly DependencyProperty ValueProperty = 4: DependencyProperty.Register("Value", "Object", typeof(SimpleSlider).FullName, 5: new PropertyMetadata(0.0, OnValueChanged)); In Visual Studio Beta 11 there is a significant improvement for the component developers. They now have all of the above missing features and can quickly begin development of Metro components. In this article you will learn how to create step by step a simple Metro component (simple slider). The blog could help component developers to ensure that they could reuse almost everything from WPF/Silverlight controls. Users without an experience in component development also could understand that is pretty easy to create XAML components for Metro applications. How to start: We will create a simple Metro application, that display information about mobile phones . In the project will be added a Templated Control item, used to implement slider functionalities. Prerequisites: Windows 8 Consumer Preview Visual Studio 11 Beta Application In Visual Studio 11 Beta create a new application: Visual C# –> Windows Metro Style –> Blank Application. Set the name of the application to “SimpleSliderDemo”. Visual Studio will create the application structure using the amazing new metro interface. Sample application will show a list with mobile phones. When you select a specified phone you could see the hone properties in the frame, located in the right side of the layout. In this application will be implemented custom slider control, that customer could use to change the number of phones in stock. SimpleSlider Control Implementation Add new item-> Templated Control and name it “SimpleSlider”. Generated Generic.xaml is in the Themes folder as you expect. Create a folder, named controls and move in this folder SimpleSlider.cs file. SimpleSlider.cs has the well known structure if you have experience with Silverlight/WPF components. There are only different namespaces for UI elements. 1: using System; 2: using System.Collections.Generic; 3: using System.Linq; 4: using Windows.UI.Xaml; 5: using Windows.UI.Xaml.Controls; 6: using Windows.UI.Xaml.Data; 7: using Windows.UI.Xaml.Documents; 8: using Windows.UI.Xaml.Input; 9: using Windows.UI.Xaml.Media; 10: 11: // The Templated Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234235 12: 13: namespace SimpleSliderDemo 14: { 15: public sealed class SimpleSlider : Control 16: { 17: public SimpleSlider() 18: { 19: this.DefaultStyleKey = typeof(SimpleSlider); 20: } 21: } 22: } Visual Studio generates also a basic template in Generic.xaml 1: <ResourceDictionary 2: xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3: xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4: xmlns:local="using:SimpleSliderDemo"> 5: 6: <Style TargetType="local:SimpleSlider"> 7: <Setter Property="Template"> 8: <Setter.Value> 9: <ControlTemplate TargetType="local:SimpleSlider"> 10: <Border 11: Background="{TemplateBinding Background}" 12: BorderBrush="{TemplateBinding BorderBrush}" 13: BorderThickness="{TemplateBinding BorderThickness}"> 14: </Border> 15: </ControlTemplate> 16: </Setter.Value> 17: </Setter> 18: </Style> 19: </ResourceDictionary> Update the SimpleSlider control template adding a thumb and a rectangle for the slider track: 1: <ResourceDictionary 2: xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3: xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4: xmlns:ctrl="using:SimpleSliderDemo.Controls"> 5: 6: <Style TargetType="ctrl:SimpleSlider"> 7: <Setter Property="Template"> 8: <Setter.Value> 9: <ControlTemplate TargetType="ctrl:SimpleSlider"> 10: <Border 11: Background="{TemplateBinding Background}" 12: BorderBrush="{TemplateBinding BorderBrush}" 13: BorderThickness="{TemplateBinding BorderThickness}"> 14: <Grid> 15: <Border Height="8" 16: VerticalAlignment="Stretch" 17: Background="LightGray" /> 18: <Canvas Margin="0" 19: MinHeight="8"> 20: <Rectangle x:Name="PART_Track" 21: Height="8" 22: Fill="Yellow" /> 23: <Thumb x:Name="PART_Thumb" Background="Blue" 24: Width="8" 25: Height="8" /> 26: </Canvas> 27: </Grid> 28: </Border> 29: </ControlTemplate> 30: </Setter.Value> 31: </Setter> 32: </Style> 33: </ResourceDictionary> Implement the slider functionalities in SimpleSlider.cs file: Add dependency properties for Value, MinValue, MaxValue Implement thumb dragging support. You could see that the approach is like in other XAML technologies. In Visual Studio 11 Beta Microsoft offers to XAML developers the same structure for components that they know from the past. You could use the overrides like OnApplyTemplate() in the same way like in WPF/Silverlight 1: using System; 2: using System.Collections.Generic; 3: using System.Linq; 4: using Windows.UI.Xaml; 5: using Windows.UI.Xaml.Controls; 6: using Windows.UI.Xaml.Controls.Primitives; 7: using Windows.UI.Xaml.Shapes; 8: using Windows.UI.Xaml.Data; 9: using Windows.UI.Xaml.Documents; 10: using Windows.UI.Xaml.Input; 11: using Windows.UI.Xaml.Media; 12: 13: // The Templated Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234235 14: 15: 16: namespace SimpleSliderDemo.Controls 17: { 18: [TemplatePart(Name = ThumbPartName, Type = typeof(Thumb))] 19: [TemplatePart(Name = TrackPartName, Type = typeof(Rectangle))] 20: public sealed class SimpleSlider : Control 21: { 22: 23: #region Fields 24: 25: private const string ThumbPartName = "PART_Thumb"; 26: private const string TrackPartName = "PART_Track"; 27: 28: private Thumb thumb; 29: private Rectangle rectangle; 30: 31: #endregion //Fields 32: 33: #region Constructor 34: public SimpleSlider() 35: { 36: this.DefaultStyleKey = typeof(SimpleSlider); 37: } 38: #endregion //Constructor 39: 40: #region Properties 41: 42: #region MinimumValue 43: 44: // Using a DependencyProperty as the backing store for MinimumValue. This enables animation, styling, binding, etc... 45: public static readonly DependencyProperty MinimumValueProperty = 46: DependencyProperty.Register("MinimumValue", typeof(object), typeof(SimpleSlider), new PropertyMetadata(0.0)); 47: 48: /// <summary> 49: /// Gets or sets the minimum. 50: /// </summary> 51: public double MinimumValue 52: { 53: get { return (double)GetValue(MinimumValueProperty); } 54: set { SetValue(MinimumValueProperty, value); } 55: } 56: 57: #endregion //MinimumValue 58: 59: #region MaximumValue 60: 61: // Using a DependencyProperty as the backing store for MaximumValue. This enables animation, styling, binding, etc... 62: public static readonly DependencyProperty MaximumValueProperty = 63: DependencyProperty.Register("MaximumValue", typeof(object), typeof(SimpleSlider), new PropertyMetadata(0.0)); 64: 65: /// <summary> 66: /// Gets or sets the maximum. 67: /// </summary> 68: public double MaximumValue 69: { 70: get { return (double)GetValue(MaximumValueProperty); } 71: set { SetValue(MaximumValueProperty, value); } 72: } 73: 74: #endregion //MaximumValue 75: 76: #region Value 77: 78: // Using a DependencyProperty as the backing store for Value. This enables animation, styling, binding, etc... 79: public static readonly DependencyProperty ValueProperty = 80: DependencyProperty.Register("Value", typeof(object), typeof(SimpleSlider), new PropertyMetadata(0.0, OnValueChanged)); 81: 82: /// <summary> 83: /// Gets or sets the value. 84: /// </summary> 85: public double Value 86: { 87: get { return (double)GetValue(ValueProperty); } 88: set 89: { 90: SetValue(ValueProperty, value); 91: } 92: } 93: #endregion //Value 94: 95: #endregion //Properties 96: 97: #region Methods 98: 99: #region OnApplyTemplate 100: /// <summary> 101: /// When overridden in a derived class, is invoked whenever application code or internal processes call <see cref="M:System.Windows.FrameworkElement.ApplyTemplate"/>. 102: /// </summary> 103: protected override void OnApplyTemplate() // OnApplyTemplateCore() 104: { 105: //base.OnApplyTemplateCore(); 106: 107: base.OnApplyTemplate(); 108: 109: this.thumb = this.GetTemplateChild(ThumbPartName) as Thumb; 110: if (this.thumb != null) 111: { 112: this.thumb.DragDelta += this.Thumb_DragDelta; 113: } 114: 115: this.rectangle = this.GetTemplateChild(TrackPartName) as Rectangle; 116: 117: this.SizeChanged += new SizeChangedEventHandler(SimpleSlider_SizeChanged); 118: } 119: #endregion //OnApplyTemplate 120: 121: #region SimpleSlider_SizeChanged 122: /// <summary> 123: /// Called when size changed. 124: /// </summary> 125: private void SimpleSlider_SizeChanged(object sender, SizeChangedEventArgs e) 126: { 127: if (e.NewSize.Width != e.PreviousSize.Width) 128: { 129: this.UpdateControlParts(); 130: } 131: } 132: #endregion //SimpleSlider_SizeChanged 133: 134: #region OnValueChanged 135: /// <summary> 136: /// Called when value changed. 137: /// </summary> 138: private static void OnValueChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) 139: { 140: var customSlider = (SimpleSlider)dependencyObject; 141: customSlider.UpdateControlParts(); 142: } 143: #endregion //OnValueChanged 144: 145: #region Thumb_DragDelta 146: /// <summary> 147: /// Handles the DragDelta event of the Thumb control. 148: /// </summary> 149: private void Thumb_DragDelta(object sender, DragDeltaEventArgs e) 150: { 151: var pixelDiff = e.HorizontalChange; 152: var currentLeft = Canvas.GetLeft(this.thumb); 153: 154: // trying to drag too far left 155: if ((currentLeft + pixelDiff) < 0) 156: { 157: this.Value = 0; 158: } 159: // trying to drag too far right 160: else if ((currentLeft + pixelDiff + this.thumb.ActualWidth) > this.ActualWidth) 161: { 162: this.Value = this.MaximumValue; 163: } 164: else 165: { 166: var totalSize = this.ActualWidth; 167: var ratioDiff = pixelDiff / totalSize; 168: var rangeSize = this.MaximumValue - this.MinimumValue; 169: var rangeDiff = rangeSize * ratioDiff; 170: this.Value += rangeDiff; 171: } 172: } 173: #endregion //Thumb_DragDelta 174: 175: #region UpdateControlParts 176: /// <summary> 177: /// Updates the control parts. 178: /// </summary> 179: private void UpdateControlParts() 180: { 181: double halfTheThumbWith = 0; 182: 183: if (this.thumb != null) 184: { 185: halfTheThumbWith = this.thumb.ActualWidth / 2; 186: } 187: 188: double totalSize = this.ActualWidth - halfTheThumbWith * 2; 189: 190: double ratio = totalSize / (this.MaximumValue - this.MinimumValue); 191: 192: if (this.thumb != null) 193: { 194: Canvas.SetLeft(this.thumb, ratio * this.Value); 195: } 196: 197: if (this.rectangle != null) 198: { 199: this.rectangle.Width = ratio * this.Value + halfTheThumbWith; 200: } 201: } 202: #endregion //UpdateControlParts 203: 204: #endregion //Methods 205: } 206: } Data This sample is focused mainly on Metro user interface and component development, but each application needs data. Add two classes: MobilePhone : to maintain phone data. MobilePhoneData: to implement a collection with a sample mobile phone data MobilePhone implementation 1: class MobilePhone : INotifyPropertyChanged 2: { 3: #region Events 4: 5: public event PropertyChangedEventHandler PropertyChanged; 6: 7: #endregion // Events 8: 9: #region Properties 10: 11: #region Id 12: 13: private long _id; 14: 15: public long Id 16: { 17: get 18: { 19: return _id; 20: } 21: 22: set 23: { 24: if (value != _id) 25: { 26: _id = value; 27: this.RaisePropertyChanged("Id"); 28: } 29: } 30: } 31: 32: #endregion // Id 33: 34: #region Brand 35: 36: private string _brand; 37: 38: public string Brand 39: { 40: get 41: { 42: return _brand; 43: } 44: 45: set 46: { 47: if (value != _brand) 48: { 49: _brand = value; 50: this.RaisePropertyChanged("Brand"); 51: } 52: } 53: } 54: 55: #endregion // Brand 56: 57: #region Model 58: 59: private string _model; 60: 61: public string Model 62: { 63: get 64: { 65: return _model; 66: } 67: 68: set 69: { 70: if (value != _model) 71: { 72: _model = value; 73: this.RaisePropertyChanged("Model"); 74: } 75: } 76: } 77: 78: #endregion // Model 79: 80: #region Price 81: 82: private string _price; 83: 84: public string Price 85: { 86: get 87: { 88: return _price; 89: } 90: 91: set 92: { 93: if (value != _price) 94: { 95: _price = value; 96: this.RaisePropertyChanged("Price"); 97: } 98: } 99: } 100: 101: #endregion // Price 102: 103: #region Quantity 104: 105: private int _quantity; 106: 107: public int Quantity 108: { 109: get 110: { 111: return _quantity; 112: } 113: 114: set 115: { 116: if (value != _quantity) 117: { 118: _quantity = value; 119: this.RaisePropertyChanged("Quantity"); 120: } 121: } 122: } 123: 124: #endregion // Quantity 125: 126: #endregion // Properties 127: 128: #region Methods 129: 130: #region RaisePropertyChanged 131: private void RaisePropertyChanged(string propertyName) 132: { 133: if (this.PropertyChanged != null) 134: { 135: this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 136: } 137: } 138: #endregion //RaisePropertyChanged 139: 140: #endregion // Methods 141: } MobilePhoneData implementation 1: class MobilePhonesData 2: { 3: #region Events 4: 5: public event PropertyChangedEventHandler PropertyChanged; 6: 7: #endregion // Events 8: 9: #region Properties 10: 11: #region Phones 12: 13: private ObservableCollection<MobilePhone> _phones; 14: 15: public ObservableCollection<MobilePhone> Phones 16: { 17: get 18: { 19: return _phones; 20: } 21: 22: set 23: { 24: if (value != _phones) 25: { 26: _phones = value; 27: RaisePropertyChanged("Phones"); 28: } 29: } 30: } 31: 32: #endregion // Phones 33: 34: #endregion // Properties 35: 36: #region Constructor 37: 38: public MobilePhonesData() 39: { 40: this.Phones = new ObservableCollection<MobilePhone> 41: { 42: new MobilePhone 43: { 44: Id = 0, 45: Brand = "Motorola", 46: Model = "GSM C139", 47: Price = "42 $", 48: Quantity = 100 49: }, 50: new MobilePhone 51: { 52: Id = 1, 53: Brand = "Motorola", 54: Model = "GSM C123", 55: Price = "46 $", 56: Quantity=120 57: }, 58: new MobilePhone 59: { 60: Id = 2, 61: Brand = "LG", 62: Model = "GSM KG275", 63: Price = "48.99 $", 64: Quantity=79 65: }, 66: 67: new MobilePhone 68: { 69: Id = 3, 70: Brand = "Sony Ericsson", 71: Model = "GSM J110i", 72: Price = "52 $", 73: Quantity=35 74: } 75: }; 76: } 77: 78: #endregion // Constructor 79: 80: #region Methods 81: 82: private void RaisePropertyChanged(string propertyName) 83: { 84: if (this.PropertyChanged != null) 85: { 86: this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 87: } 88: } 89: 90: #endregion // Methods 91: } Mobile Phone Details Add a blank page for Mobile Phone Details. In this page application will display details about the selected mobile phone 1: <Page 2: x:Class="SimpleSliderDemo.PhoneDetailsPage" 3: xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 4: xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 5: xmlns:local="using:SimpleSliderDemo" 6: xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 7: xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 8: mc:Ignorable="d"> 9: 10: <Grid Background="{StaticResource ApplicationPageBackgroundBrush}"> 11: <StackPanel Orientation="Vertical"> 12: <TextBlock Text="Mobile Phone:" FontSize="36"/> 13: <TextBlock Text="{Binding Brand}" FontSize="32"/> 14: <TextBlock Text="{Binding Model}" FontSize="32"/> 15: <StackPanel Orientation="Horizontal"> 16: <TextBlock Text="Price=" FontSize="32"/> 17: <TextBlock Text="{Binding Price}" FontSize="32"/> 18: </StackPanel> 19: 20: <StackPanel Orientation="Horizontal"> 21: <TextBlock Text="Quantity=" FontSize="32"/> 22: <TextBlock Text="{Binding Quantity}" FontSize="32"/> 23: </StackPanel> 24: </StackPanel> 25: </Grid> 26: </Page> When navigate to this page you could set Parameter (selected mobile phone) as a DataContext for PhoneDetailsPage. 1: protected override void OnNavigatedTo(NavigationEventArgs e) 2: { 3: this.DataContext = e.Parameter; 4: } Application usage Run the application. You could see the list with phones. When you select a phone details about the specified product appears in the frame where is loaded the phone details page. Slider thumb shows the number of items on stock (Quantity). User could change the number of available phones when you drag the slider thumb Finally you have a real XAML WinRT component for Metro applications. It is easy, very similar to other XAML platforms and could give an opportunity to be one of the first on this market. Source code you could download here. Follow news from Infragistics in http://infragistics.com/ and twitter: @infragistics for more information about new Infragistics products.