You are here

Feed aggregator

Combining wave containerization, work break and cluster picking to support a piece picking operation – AX2012R3

MSDN Blogs - Wed, 08/27/2014 - 00:30
Posted on behalf of Lars Frandsen. Introduction Many distribution centers are seeing order profiles trending toward smaller orders with fewer lines, and lower quantities per work line. This leads to distribution centers being tasked with the piece pick process, which is also known as broken case or less-than-case picking. The piece picking process is one of the most complex and labor-intensive processes for picking orders. To reduce travel time in the warehouse, multiple orders can be grouped...(read more)

Microsoft Educast - PC or Chromebook?

MSDN Blogs - Wed, 08/27/2014 - 00:30

Great Educast episode discussing the differences between PC’s and Chromebooks and why a Windows PC is the right choice for education.

(Please visit the site to view this video)

Microsoft Educast - PC or Chromebook?

MSDN Blogs - Wed, 08/27/2014 - 00:30

Great Educast episode discussing the differences between PC’s and Chromebooks and why a Windows PC is the right choice for education.

(Please visit the site to view this video)

Microsoft Educast - PC or Chromebook?

MSDN Blogs - Wed, 08/27/2014 - 00:30

Great Educast episode discussing the differences between PC’s and Chromebooks and why a Windows PC is the right choice for education.

(Please visit the site to view this video)

Announcing the Release Candidates for Web API OData 5.3

MSDN Blogs - Wed, 08/27/2014 - 00:22

The release candidate NuGet packages for ASP.NET Web API OData 5.3 are now live on the NuGet gallery!

Download this release

You can install or update the release candidate NuGet packages for ASP.NET Web API OData 5.3 using the NuGet Package Manager Console, like this:

  • Install-Package Microsoft.AspNet.OData -Version 5.3.0-rc -Pre
  • Install-Package Microsoft.AspNet.WebApi.OData -Version 5.3.0-rc -Pre

What’s in this release?

This release primarily includes great new features for Web API OData v4 as summarized below:

ASP.NET Web API OData 5.3 Release Candidate

Additional Documentation

Tutorials and other information about Web API OData are available from the ASP.NET web site (http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api).

Questions and feedback

You can submit questions related to this release on the ASP.NET Web API forums. Please submit any issues you encounter and feature suggestions for future releases on our CodePlex site.

Thanks and enjoy!

プログラミング Windows 第6版 第11章 WPF編

MSDN Blogs - Tue, 08/26/2014 - 23:20

この記事では、「プログラミング Windows 第6版」を使って WPF XAML の学習を支援することを目的にしています。この目的から、書籍と併せて読まれることをお勧めします。

第11章 3つのテンプレート

本章では、タイトルにあるように 3種類のテンプレート(コントロール テンプレート、データ テンプレート、アイテム テンプレート)を説明しています。データ テンプレートは、データバインドを行う場合に活用されるもので、ContentControl を継承するクラスで使用されます。コントロール テンプレートは、コントロールの外観を再定義するために使用するもので、マウスなどの動きに応じてコントロールの外観を変化させるアニメーションの定義なども含まれています。最後のアイテム テンプレートは、コレクションをデータ バインドした時に個々のデータに適用されるテンプレートになります。たとえば、リスト ボックスなどのアイテムに適用されるのがアイテム テンプレートです。書籍にも記述がありますが、これらのテンプレートを作成したりカスタマイズするのであれば、Blend for Visual Studio の操作に慣れておくことをお勧めします。その理由は、Blend ではテンプレートをビジュアルに編集することが容易だからです。テンプレートの編集では、Visual Studio のデザイナーは Blend よりも非力になります。

11.1(P494) ボタンのデータ

本節では、Button コントロールの Content プロパティを使ってどのように外観を定義できるかを具体例を使って説明しています。最初に Image オブジェクトを使い、次に Ellipse と LinearGradientBrush を組み合わせてから、テンプレートをリソースに定義することを説明しています。ここまでの説明をしてから、Button に対するスタイル定義を説明するために、SharedStyleWithDataTemplate プロジェクトの MainWindow.xaml の抜粋を示します。

<Window ... > <Window.Resources> <Style TargetType="Button"> <Setter Property="HorizontalAlignment" Value="Center" /> <Setter Property="VerticalAlignment" Value="Center" /> <Setter Property="ContentTemplate"> <Setter.Value> <DataTemplate> <Ellipse Width="144" Height="192" Fill="{Binding}" /> </DataTemplate> </Setter.Value> </Setter> </Style> </Window.Resources> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="*" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Button Grid.Column="0"> <SolidColorBrush Color="Green" /> </Button> <Button Grid.Column="1"> <LinearGradientBrush> <GradientStop Offset="0" Color="Blue" /> <GradientStop Offset="1" Color="Red" /> </LinearGradientBrush> </Button> <Button Grid.Column="2"> <ImageBrush ImageSource="http://www.charlespetzold.com/pw6/PetzoldJersey.jpg" /> </Button> </Grid> </Window>

この XAML は、組み込みのスタイルを除けば WinRT XAML と同じになります。それでは、実行結果を示します。

今度は、時計を表示するボタンの外観を作成するために ClockButton プロジェクトの Clock.cs を示します。

using System; using System.ComponentModel; using System.Runtime.CompilerServices; using System.Windows.Media; namespace ClockButton { public class Clock : INotifyPropertyChanged { bool isEnabled; int hour, minute, second; int hourAngle, minuteAngle, secondAngle; public event PropertyChangedEventHandler PropertyChanged; public bool IsEnabled { set { if (SetProperty<bool>(ref isEnabled, value, "IsEnabled")) { if (isEnabled) CompositionTarget.Rendering += OnCompositionTargetRendering; else CompositionTarget.Rendering -= OnCompositionTargetRendering; } } get { return isEnabled; } } public int Hour { set { SetProperty<int>(ref hour, value); } get { return hour; } } public int Minute { set { SetProperty<int>(ref minute, value); } get { return minute; } } public int Second { set { SetProperty<int>(ref second, value); } get { return second; } } public int HourAngle { set { SetProperty<int>(ref hourAngle, value); } get { return hourAngle; } } public int MinuteAngle { set { SetProperty<int>(ref minuteAngle, value); } get { return minuteAngle; } } public int SecondAngle { set { SetProperty<int>(ref secondAngle, value); } get { return secondAngle; } } void OnCompositionTargetRendering(object sender, object args) { DateTime dateTime = DateTime.Now; this.Hour = dateTime.Hour; this.Minute = dateTime.Minute; this.Second = dateTime.Second; this.HourAngle = 30 * dateTime.Hour + dateTime.Minute / 2; this.MinuteAngle = 6 * dateTime.Minute + dateTime.Second / 10; this.SecondAngle = 6 * dateTime.Second + dateTime.Millisecond / 166; } protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null) { if (object.Equals(storage, value)) return false; storage = value; OnPropertyChanged(propertyName); return true; } protected virtual void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } }

このコードは、WinRT XAML と同じになります。そして、作成した Clock クラスをデータソースとして使用する ClockButton プロジェクトの MainWindow.xaml の抜粋を示します。

<Grid> <Button HorizontalAlignment="Center" VerticalAlignment="Center"> <local:Clock IsEnabled="True" /> <Button.ContentTemplate> <DataTemplate> <Grid Width="144" Height="144"> <Grid.Resources> <Style TargetType="Polyline"> <Setter Property="Stroke" Value="Black" /> </Style> </Grid.Resources> <Polyline Points="72 80, 72 24" StrokeThickness="6"> <Polyline.RenderTransform> <RotateTransform Angle="{Binding HourAngle}" CenterX="72" CenterY="72" /> </Polyline.RenderTransform> </Polyline> <Polyline Points="72 88, 72 12" StrokeThickness="3"> <Polyline.RenderTransform> <RotateTransform Angle="{Binding MinuteAngle}" CenterX="72" CenterY="72" /> </Polyline.RenderTransform> </Polyline> <Polyline Points="72 88, 72 6" StrokeThickness="1"> <Polyline.RenderTransform> <RotateTransform Angle="{Binding SecondAngle}" CenterX="72" CenterY="72" /> </Polyline.RenderTransform> </Polyline> </Grid> </DataTemplate> </Button.ContentTemplate> </Button> </Grid>

この XAML は、組み込みのスタイルを除けば WinRT XAML と同じになります。それでは、実行結果を示します。

書籍には、ボタンのしての動き(たとえば、クリックした場合)などの説明がありますし、外観をどのように変更したかなどの説明もあります。それでも、書籍と併せてここまでを読むだけでも、Button コントロールでも様々な外観にテンプレートを使うことでカスタマイズができることを理解できることでしょう。このカスタマイズ性は、XAML 系 UI 技術の特徴でもあり、Windows Forms には無いものになります。

11.2(P504) 意志決定

本節では、XAML の記述だけでは条件分岐などができないことから、11.1 の ClockButton プロジェクトの Clock クラスを利用して拡張することで条件によって外観を変更することを説明しています。それでは、ConditionalClockButton クラスの TwelveHourColck.cs を示します。

namespace ConditionalClockButton { public class TwelveHourClock : ClockButton.Clock { // Initialize for Hour value of 0 int hour12 = 12; bool isAm = true; bool isPm = false; public int Hour12 { set { SetProperty<int>(ref hour12, value); } get { return hour12; } } public bool IsAm { set { SetProperty<bool>(ref isAm, value); } get { return isAm; } } public bool IsPm { set { SetProperty<bool>(ref isPm, value); } get { return isPm; } } protected override void OnPropertyChanged(string propertyName) { if (propertyName == "Hour") { this.Hour12 = (this.Hour - 1) % 12 + 1; this.IsAm = this.Hour < 12; this.IsPm = !this.IsAm; } base.OnPropertyChanged(propertyName); } } }

このコードは、WinRT XAML と同じになります。次に表示を切り替えるために、BooleanToVisibilityConverter.cs を示します。

using System; using System.Windows; using System.Windows.Data; namespace ConditionalClockButton { public sealed class BooleanToVisibilityConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { return (bool)value ? Visibility.Visible : Visibility.Collapsed; } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { return (Visibility)value == Visibility.Visible; } } }

コードは、名前空間とConvert メソッドと ConvertBack メソッドの第4パラメーターを除けば WinRT XAML と同じになります。すでに説明していますが、Windows ストア アプリのプロジェクトと違うので WPF XAML では、サンプルになるようなコンバーターのコードはプロジェクトに含まれていません。それでは、ConditionalClockButton プロジェクトの MainWindow.xaml の抜粋を示します。

<Grid> <Button HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="24"> <local:TwelveHourClock IsEnabled="True" /> <Button.ContentTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <StackPanel.Resources> <local:BooleanToVisibilityConverter x:Key="booleanToVisibility" /> </StackPanel.Resources> <TextBlock Text="It's after " /> <TextBlock Text="{Binding Hour12}" /> <TextBlock Text=" o'clock" /> <TextBlock Text=" in the morning!" Visibility="{Binding IsAm, Converter={StaticResource booleanToVisibility}}" /> <TextBlock Text=" in the afternoon!" Visibility="{Binding IsPm, Converter={StaticResource booleanToVisibility}}" /> </StackPanel> </DataTemplate> </Button.ContentTemplate> </Button> </Grid>

このコードは、組み込みのスタイルを除けば WinRT XAML と同じになります。書籍に説明がありますが、今までと異なるのはリソースの定義が StackPanle に定義されていることになります。これは、リソースを扱った章で説明していますが、リソースは様々な要素に定義できることの一例でしかありません。このように定義することで、StackPanel の中だけで使用できるリソースとなります。つまり、リソースのスコープを定義したわけです。それでは、実行結果を示します。

11.3(P508) コレクション コントロールと DataTemplate の本来の使用方法

本節では、DataTemplate を使用すべき場面を説明しています。そのために、ItemControl を使ってコレクションがどのように表示されるかを説明しています。ここまでの説明が済んでから、DataTemplate の具体例を説明します。そして、DataTemplate の使い方を説明するために ColorItems プロジェクトの MainWindow.xaml の抜粋を示します。

<Grid> <ScrollViewer> <ItemsControl x:Name="itemsControl" FontSize="24"> <ItemsControl.ItemTemplate> <DataTemplate> <Grid Width="240" Margin="0 12"> <Grid.ColumnDefinitions> <ColumnDefinition Width="144" /> <ColumnDefinition Width="Auto" /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <Rectangle Grid.Column="0" Grid.Row="0" Grid.RowSpan="4" Margin="12 0"> <Rectangle.Fill> <SolidColorBrush Color="{Binding}" /> </Rectangle.Fill> </Rectangle> <StackPanel Grid.Column="1" Grid.Row="0" Orientation="Horizontal"> <TextBlock Text="A = " /> <TextBlock Text="{Binding A}" /> </StackPanel> <StackPanel Grid.Column="1" Grid.Row="1" Orientation="Horizontal"> <TextBlock Text="R = " /> <TextBlock Text="{Binding R}" /> </StackPanel> <StackPanel Grid.Column="1" Grid.Row="2" Orientation="Horizontal"> <TextBlock Text="G = " /> <TextBlock Text="{Binding G}" /> </StackPanel> <StackPanel Grid.Column="1" Grid.Row="3" Orientation="Horizontal"> <TextBlock Text="B = " /> <TextBlock Text="{Binding B}" /> </StackPanel> </Grid> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> </ScrollViewer> </Grid>

この XAML は、組み込みのスタイルを除けば WinRT XAML と同じになります。そして、データを設定するための MainWindow.xaml.cs の抜粋を示します。

public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); IEnumerable<PropertyInfo> properties = typeof(Colors).GetTypeInfo().DeclaredProperties; foreach (PropertyInfo property in properties) { Color clr = (Color)property.GetValue(null); itemsControl.Items.Add(clr); } } }

このコードは、WinRT XAML と同じになります。Colors 列挙をリフレクションによって、ItemControls の Items コレクションに追加しています。それでは、実行結果を示します。

実行結果には、色の名前が含まれていないことから、これを解決するため�� Petzold.ProgrammingWindows6.Chapter11 プロジェクトの NamedColor.cs を示します。

using System.Collections.Generic; using System.Reflection; using System.Windows.Media; namespace Petzold.ProgrammingWindows6.Chapter11 { public class NamedColor { static NamedColor() { List<NamedColor> colorList = new List<NamedColor>(); IEnumerable<PropertyInfo> properties = typeof(Colors).GetTypeInfo().DeclaredProperties; foreach (PropertyInfo property in properties) { NamedColor namedColor = new NamedColor { Name = property.Name, Color = (Color)property.GetValue(null) }; colorList.Add(namedColor); } All = colorList; } public static IEnumerable<NamedColor> All { private set; get; } public string Name { private set; get; } public Color Color { private set; get; } } }

このコードは、WinRT XAML と同じになります。そして、INotifyPropertyChanged インタフェースを実装していない理由なども書籍では説明しています。この理由は、単純でデータが動的に変化しないためです。そして、次に色の成分値を 16進数に変換するコンバーターである ByteToHexStringConverter.cs を示します。

using System; using System.Windows.Data; namespace Petzold.ProgrammingWindows6.Chapter11 { public class ByteToHexStringConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { return ((byte)value).ToString("X2"); } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { return value; } } }

このコードは、名前空間とConvert メソッドと ConvertBack メソッドの第4パラメーターを除けば WinRT XAML と同じになります。それでは、これらのクラスを使用する ColorItemsSource プロジェクトの MainWindow.xaml の抜粋を示します。

<Window ... xmlns:ch11="clr-namespace:Petzold.ProgrammingWindows6.Chapter11;assembly=Petzold.ProgrammingWindows6.Chapter11" ... > <Window.Resources> <ch11:ByteToHexStringConverter x:Key="byteToHexString" /> </Window.Resources> <Grid> <ScrollViewer> <ItemsControl x:Name="itemsControl"> <ItemsControl.ItemTemplate> <DataTemplate> <Border BorderBrush="Black" BorderThickness="1" Width="336" Margin="6"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <Rectangle Grid.Column="0" Height="72" Width="72" Margin="6"> <Rectangle.Fill> <SolidColorBrush Color="{Binding Color}" /> </Rectangle.Fill> </Rectangle> <StackPanel Grid.Column="1" VerticalAlignment="Center"> <TextBlock FontSize="24" Text="{Binding Name}" /> <ContentControl FontSize="18"> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding Color.A, Converter={StaticResource byteToHexString}}" /> <TextBlock Text="-" /> <TextBlock Text="{Binding Color.R, Converter={StaticResource byteToHexString}}" /> <TextBlock Text="-" /> <TextBlock Text="{Binding Color.G, Converter={StaticResource byteToHexString}}" /> <TextBlock Text="-" /> <TextBlock Text="{Binding Color.B, Converter={StaticResource byteToHexString}}" /> </StackPanel> </ContentControl> </StackPanel> </Grid> </Border> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> </ScrollViewer> </Grid> </Window>

この XAML は、名前空間「xmlns:ch11」の定義方法と組み込みのスタイルを除けば WinRT XAML と同じになります。それでは、データ ソースを設定する MainWindow.xam.cs の抜粋を示します。

public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); itemsControl.ItemsSource = NamedColor.All; } }

このコードは、WinRT XAML と同じになります。それでは、実行結果を示します。

今度は、コードを使用しないでデータ バインディングを行う ColorItemsSourceWithBinding プロジェクトの MainWindow.xaml の抜粋を示します。

<Window ... xmlns:ch11="clr-namespace:Petzold.ProgrammingWindows6.Chapter11;assembly=Petzold.ProgrammingWindows6.Chapter11" ... > <Window.Resources> <ch11:NamedColor x:Key="namedColor" /> <ch11:ByteToHexStringConverter x:Key="byteToHexString" /> </Window.Resources> <Grid> <ScrollViewer> <ItemsControl ItemsSource="{Binding Source={StaticResource namedColor}, Path=All}"> <ItemsControl.ItemTemplate> <DataTemplate> <Border BorderBrush="Black" BorderThickness="1" Width="336" Margin="6"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <Rectangle Grid.Column="0" Height="72" Width="72" Margin="6"> <Rectangle.Fill> <SolidColorBrush Color="{Binding Color}" /> </Rectangle.Fill> </Rectangle> <StackPanel Grid.Column="1" VerticalAlignment="Center"> <TextBlock FontSize="24" Text="{Binding Name}" /> <ContentControl FontSize="18"> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding Color.A, Converter={StaticResource byteToHexString}}" /> <TextBlock Text="-" /> <TextBlock Text="{Binding Color.R, Converter={StaticResource byteToHexString}}" /> <TextBlock Text="-" /> <TextBlock Text="{Binding Color.G, Converter={StaticResource byteToHexString}}" /> <TextBlock Text="-" /> <TextBlock Text="{Binding Color.B, Converter={StaticResource byteToHexString}}" /> </StackPanel> </ContentControl> </StackPanel> </Grid> </Border> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> </ScrollViewer> </Grid> </Window>

この XAML は、名前空間の記述と組み込みのスタイルを除けば WinRT XAML と同じになります。もちろん、実行結果も ColorItemsSource プロジェクトと同じになります。「コレクションとデータ バインディングとテンプレートの組み合わせです。WinRT プログラミングの本質はそこにあります」(書籍より引用)と書籍に記述されていますが、これは XAML 系 UI 技術に共通する特徴ですから、WPF XAML にも当てはまります。また、書籍ではDataTemplate の定義内容などを説明していますので、書籍の熟読をお願いします。

11.4(P520) コレクションとインタフェース

本節では、コレクションをバインディングするために使用されている IEnumerable<T> インタフェースや IDictionary<TKey, TValue> インタフェース、INotifyPropertyChanged インタフェース、INotifyCollectionChanged インタフェースと WinRT の関係を説明しています。WinRT と .NET Framework のコレクションは、透過的に使えるようにプロジェクションという仕組みが用意されています。そして、データ バインディングを考える上で、本節の説明は WPF XAML にも当てはまりますので書籍の熟読をお願いします。

11.5(P522) タップと選択

本節では、DataTemplate で表現されるデータを選択するためにタップ イベントでどのように処理するかを説明しています。そして、選択したアイテムを使う SimpleListBox プロジェクトの Mainwindow.xaml の抜粋を示します。

<Window ... > <Window.Resources> <ch11:NamedColor x:Key="namedColor" /> </Window.Resources> <Grid> <ListBox Name="lstbox" ItemsSource="{Binding Source={StaticResource namedColor}, Path=All}" DisplayMemberPath="Name" Width="288" HorizontalAlignment="Center" /> <Grid.Background> <SolidColorBrush Color="{Binding ElementName=lstbox, Path=SelectedItem.Color}" /> </Grid.Background> </Grid> </Window>

この XAML は、WinRT XAML と同じになります。Grid の Background にリストボックスで選択した色をバインディングしていることが、XAML から理解できることでしょう。それでは、実行結果を示します。

書籍では、SelectedValuePath プロパティなどの使い方を説明してから、ListBox の ItemTemplate に DataTemplate を使用する説明をしています。それでは、ListBoxWithItemTemplate プロジェクトの MainWindow.xaml の抜粋を示します。

<Window ... > <Window.Resources> <ch11:NamedColor x:Key="namedColor" /> </Window.Resources> <Grid> <ListBox Name="lstbox" ItemsSource="{Binding Source={StaticResource namedColor}, Path=All}" Width="380"> <ListBox.ItemTemplate> <DataTemplate> <Border BorderBrush="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Foreground}" BorderThickness="1" Width="336" Margin="6" Loaded="OnItemLoaded"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <Rectangle Grid.Column="0" Height="72" Width="72" Margin="6"> <Rectangle.Fill> <SolidColorBrush Color="{Binding Color}" /> </Rectangle.Fill> </Rectangle> <TextBlock Grid.Column="1" FontSize="24" Text="{Binding Name}" VerticalAlignment="Center" /> </Grid> </Border> </DataTemplate> </ListBox.ItemTemplate> </ListBox> <Grid.Background> <SolidColorBrush Color="{Binding ElementName=lstbox, Path=SelectedItem.Color}" /> </Grid.Background> </Grid> </Window>

この XAML は、WinRT XAML と同じになります。それでは、実行結果を示します。

書籍では、特殊なデータ バインディング記述として「TemplatedParent」を説明しています。もちろん、組み込みのスタイルを除けば WPF XAML にも共通します。このことは、XAML そのものを大きく変更していないことでも明らかですから、詳しい説明は書籍を参照してください。

11.6(P527) 見えるパネルと見えないパネル

本節では、ListBoxWithItemTemplate プロジェクトの Border に対する Loaded イベント ハンドラーを使って UI の仮想化を説明しています。仮想化を説明してから、ItemPanelTemplate の説明になります。それでは、ItemPanleTemplate を使用する HorizontalListBox プロジェクトの MainWindow.xaml の抜粋を示します。

<Window ... > <Window.Resources> <ch11:NamedColor x:Key="namedColor" /> </Window.Resources> <Grid> <ListBox Name="lstbox" ItemsSource="{Binding Source={StaticResource namedColor}, Path=All}" Height="120" ScrollViewer.HorizontalScrollBarVisibility="Auto" ScrollViewer.VerticalScrollBarVisibility="Disabled"> <ListBox.ItemTemplate> <DataTemplate> <Border BorderBrush="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Foreground}" BorderThickness="1" Width="336" Margin="6" Loaded="OnItemLoaded"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <Rectangle Grid.Column="0" Height="72" Width="72" Margin="6"> <Rectangle.Fill> <SolidColorBrush Color="{Binding Color}" /> </Rectangle.Fill> </Rectangle> <TextBlock Grid.Column="1" FontSize="24" Text="{Binding Name}" VerticalAlignment="Center" /> </Grid> </Border> </DataTemplate> </ListBox.ItemTemplate> <ListBox.ItemsPanel> <ItemsPanelTemplate> <VirtualizingStackPanel Orientation="Horizontal" /> </ItemsPanelTemplate> </ListBox.ItemsPanel> </ListBox> <Grid.Background> <SolidColorBrush Color="{Binding ElementName=lstbox, Path=SelectedItem.Color}" /> </Grid.Background> </Grid> </Window>

この XAML は、ScrollViewer の HorizontalScrollMode と VerticalScrollMode プロパティを除けば WinRT XAML と同じになります。WinRT XAML の HorizontalScrollMode と VerticalScrollMode プロパティは、ScrollMode 列挙を指定するものであり、WPF XAML では Panning プロパティに相当するものになります。Panning プロパティとは、タッチ操作におけるスクロールを制御するためのプロパティですから、タッチ対応にするのであれば指定した方が良いでしょう。Panning プロパティを指定しなかった場合は、デフォルトでパン ジェスチャが有効になっています。そして、ItemsPanelTemplate に VirtualizingStackPanel を指定して 水平方向(Horizontal) に指定していますから、アイテムが縦方向ではなく横(水平)方向に表現されることとなります。それでは、実行結果を示します。

書籍には、ItemsPanelTemplate の説明がありますので熟読をお願いします。UI の仮想化は、Windows Forms になく XAML 系 の UI 技術の特徴でもあり、高速化に寄与しています。WinRT XAML では、UI の仮想化だけではなくデータの仮想化もサポートされていますので、興味があれば自分で調べることをお勧めします。

11.7(P532) カスタム パネル

本節では、WrapGrid や VariableSizedWrapGrid パネルがうまく使えないことを出発点にして、独自のカスタム パネルを定義するために必要な事項を説明しています。そして、WPF XAML に含まれている UniformGrid パネルを独自に定義することに説明が移ります。しかし、この記事は WPF XAML なので、UniformGrid が標準提供されていますから、WinRT XAML のように UniformGrid を独自に定義する必要はありません。もし、カスタム パネルを自分で作成したい場合は書籍や「Applications = Code + Markup」など参考にするのと WPF Toolkit などの具体例なども参考にしてください。それでは、UniformGrid パネルを使用する AllColorsItemsControl プロジェクトの MainWindow.xaml の抜粋を示します。

<Window ... > <Window.Resources> <ch11:NamedColor x:Key="namedColor" /> <ch11:ColorToContrastColorConverter x:Key="colorConverter" /> </Window.Resources> <Grid> <ItemsControl ItemsSource="{Binding Source={StaticResource namedColor}, Path=All}"> <ItemsControl.ItemTemplate> <DataTemplate> <Border BorderBrush="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Foreground}" BorderThickness="2" Margin="2"> <Border.Background> <SolidColorBrush Color="{Binding Color}" /> </Border.Background> <Viewbox> <TextBlock Text="{Binding Name}" HorizontalAlignment="Center" VerticalAlignment="Center"> <TextBlock.Foreground> <SolidColorBrush Color="{Binding Color, Converter={StaticResource colorConverter}}" /> </TextBlock.Foreground> </TextBlock> </Viewbox> </Border> </DataTemplate> </ItemsControl.ItemTemplate> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <UniformGrid /> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> </ItemsControl> </Grid> </Window>

この XAML は、組み込みスタイルと「ch11:UniformGrid」を除けば WinRT XAML と同じになります。次にモノクロ諧調を計算する Petzold.ProgrammingWindows6.Chapter11 プロジェクトの ColorToContrastColorConverter.cs を示します。

using System; using System.Windows.Data; using System.Windows.Media; namespace Petzold.ProgrammingWindows6.Chapter11 { public class ColorToContrastColorConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { Color clr = (Color)value; double grayShade = 0.30 * clr.R + 0.59 * clr.G + 0.11 * clr.B; return grayShade > 128 ? Colors.Black : Colors.White; } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { return value; } } }

この コードは、Convert と ConvertBack メソッドの第4引数を除けば WinRT XAML と同じになります。それでは、実行結果を示します。

実は、Petzold.ProgrammingWindows6.Chapter11 プロジェクトに定義されている UniformGrid も WPF 向けに移植してあります(UniformGrid2 クラス)。でも、ウィンドウ サイズをリサイズした場合の表示がうまく行っていません。多分、MeasureOverride メソッドなどで適切なサイズを計算できていないのが原因だと思われます。書籍を WPF XAML に置き換えての説明という観点では標準の UniformGrid で目的を達成できていますので、興味がある方が UniformGrid2 クラスを完成させて頂ければと思います。完成したならば、どこかに記事を掲載してください。そうすることで、WPF を学ぶ人にとって有益なものになることでしょう。

今度は、Border 要素と TextBlock 要素にサイズ指定した ListBoxWithUniformGrid プロジェクトの MainWindow.xaml の抜粋を示します。

<Window ... > <Window.Resources> <ch11:NamedColor x:Key="namedColor" /> <ch11:ColorToContrastColorConverter x:Key="colorConverter" /> </Window.Resources> <Grid> <ListBox ItemsSource="{Binding Source={StaticResource namedColor}, Path=All}"> <ListBox.ItemTemplate> <DataTemplate> <Border BorderBrush="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Foreground}" Width="288" Height="72" BorderThickness="3" Margin="3"> <Border.Background> <SolidColorBrush Color="{Binding Color}" /> </Border.Background> <TextBlock Text="{Binding Name}" FontSize="24" HorizontalAlignment="Center" VerticalAlignment="Center"> <TextBlock.Foreground> <SolidColorBrush Color="{Binding Color, Converter={StaticResource colorConverter}}" /> </TextBlock.Foreground> </TextBlock> </Border> </DataTemplate> </ListBox.ItemTemplate> <ListBox.ItemsPanel> <ItemsPanelTemplate> <UniformGrid /> </ItemsPanelTemplate> </ListBox.ItemsPanel> </ListBox> </Grid> </Window>

この XAML は、AllCorlorsItemsControl と同じ箇所だけを WPF XAML 用に変更しています。Border に Width と Height を指定した結果は、WinRT XAML と同じで正しく表示されています。そでは、実行結果を示します。

ListBoxWithUniformGrid プロジェクト で、UniformGrid を Petzold.ProgrammingWindows6.Chapter11 プロジェクトに定義されている UniformGrid2 に置き換える場合は、Rows か Columns プロパティを明示的に指定することで正常に動作します。つまり、書籍にも記述されていますが利用可能な幅と子要素の最大幅に基づいて、列の数を割り出すロジックなどにおいて WinRT XAML との違いがあることになります。これらの問題を解消すれば、WPF XAML 用のカスタム パネルである UniformGrid2 を完成させることができることでしょう。書籍では、スクロールの切り替え方なども説明していますので、書籍の熟読をお願いします。

11.8(P546) アイテム テンプレートによる棒グラフ

本節では、表題の通りアイテム テンプレートを使って棒グラフを描画するアイテム テンプレートを説明しています。それでは、RgbBarChart プロジェクトの MainWindow.xaml の抜粋を示します。

<Window ... > <Window.Resources> <ch11:NamedColor x:Key="namedColor" /> <ch11:ByteToHexStringConverter x:Key="byteToHex" /> </Window.Resources> <Grid> <ItemsControl ItemsSource="{Binding Source={StaticResource namedColor}, Path=All}"> <ItemsControl.ItemTemplate> <DataTemplate> <StackPanel Name="stackPanel" Height="765" RenderTransformOrigin="0.5 0.5" Margin="1 0" > <StackPanel.RenderTransform> <ScaleTransform ScaleY="-1" /> </StackPanel.RenderTransform> <Rectangle Fill="Red" Height="{Binding Color.R}" /> <Rectangle Fill="Green" Height="{Binding Color.G}" /> <Rectangle Fill="Blue" Height="{Binding Color.B}" /> <ToolTipService.ToolTip> <ToolTip x:Name="tooltip" PlacementTarget="{Binding ElementName=stackPanel}"> <Grid> <StackPanel > <TextBlock Text="{Binding Name}" HorizontalAlignment="Center" /> <StackPanel DataContext="{Binding Color}" Orientation="Horizontal" HorizontalAlignment="Center"> <TextBlock Text="R=" /> <TextBlock Text="{Binding R}" /> <TextBlock Text=" G=" /> <TextBlock Text="{Binding G}" /> <TextBlock Text=" B=" /> <TextBlock Text="{Binding B}" /> </StackPanel> </StackPanel> </Grid> </ToolTip> </ToolTipService.ToolTip> </StackPanel> </DataTemplate> </ItemsControl.ItemTemplate> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <UniformGrid Rows="1" /> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> </ItemsControl> </Grid> </Window>

この XAML は、組み込みのスタイルと Grid の DataContext、StackPanel の DataContext を除けば WinRT XAML と同じになります。この DataContext の指定方法は、WinRT XAML と WPF XAML で異なる動作をするものになっています。それでは、実行結果を示します。

結論から言えば、WPF XAML のアイテム テンプレートではバインディングされたアイテムが ToolTip であっても自動的に反映されるために「Grid DataContext="{Binding ElementName=tooltip, Path=PlacementTarget}"」を記述してはいけません。記述してしまうと、記述に従って StackPanel へバインディングされるために何も表示されなくなります。一方で WinRT XAML では、Tooltip は表示を行う時にバインディングが解決されるような動きをしています。つまり、「Grid DataContext="{Binding ElementName=tooltip, Path=PlacementTarget}"」の記述によって ToolTip を表示する時に StackPanel の DataContext へとデータソースが解決されます。この動きによって、期待通りに ToolTip が表示されるようになります。この動きの違いは、WPF XAML はフルスタックのフレームワークであり ToolTip を含めて統一的にデータソースが解決されるからであり、WinRT XAML では必要がないものは必要とされるまで解決しない(実行速度を優先)という考え方に基づいたサブセットと考えると理解し易いかも知れません。この RdbBarChart プロジェクトの WPF XAML 版の欠点は、グラフの大きさが固定されているのでウィンドウのリサイズに対応できないことです。この点については、グラフの高さを計算するロジックにウィンドウ サイズを加味し、サイズ変更イベントの処理を組み合わせれば解決することができますので、自分で挑戦してみてください。もちろん、書籍にあるように RenderTransform プロパティで調整するのでも構いません。

11.9(P548) FlipView コントロール

本節では、WinRT XAML に導入された FlipView コントロールを使ってアイテム テンプレートを使用する方法を説明しています。従って、WPF XAML ではアイテム テンプレートの説明を別のコントロールに流用することはできますが、WinRT の FlipView のようなコントロールを使いたいとすると、自分で作成するか、サードパーティー製のコントロールを使用することになります。たとえば、DevExpress の製品などになります。

11.10(P551) 基本的なコントロール テンプレート

本節では、DataTemplate、ItemsPanelTemplate に続く 3つ目のテンプレートとして ControlTemplate の説明をしています。ControlTemplate の説明として、Style に始まり、ControlTemplate へと続き、TemplateBinding を説明し、ContentPresenter の説明へと続きます。ほとんどの説明が、WPF XAML にも利用できますので、書籍の熟読をお願いします。

11.11(P562) ビジュアル状態マネージャー

本節では、コントロールがユーザー操作に反応するフィードバックを定義するビジュアル状態マネージャー(VisualStateManager)の説明をしています。この説明のために Button コントロールを使用して、7つのビジュアル状態を説明し、2つのグループに分類されることを説明しています。

  • CommonStates
    Normal、MouseOrver、Pressed、Disabled
  • FocusStates (WinRT では、FocusedStates)
    Forcused、Unforcused

WinRT XAML と WPF XAML では、ビジュアル状態の状態名が少し異なっています。具体例を次に示します。

WinRT WPF グループ PointOrver MouseOrver CommonStates PointerFocused 無し FocusStates

この点に注意すれば、WinRT XAML のサンプルや WPF XAML のサンプルを相互に書き換えることができます。書籍では、これらのビジュアル状態の定義と ContentPresenter の使い方を説明してから、カスタム ボタンを定義した全体像を示します。それでは、CustomButtonTemplate プロジェクトの MainWindow.xaml の抜粋を示します。

<Window ... > <Window.Resources> <ControlTemplate x:Key="buttonTemplate" TargetType="Button"> <Grid> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CommonStates"> <VisualState x:Name="Normal" /> <VisualState x:Name="MouseOver" /> <VisualState x:Name="Pressed"> <Storyboard> <ColorAnimationUsingKeyFrames Storyboard.TargetName="border" Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)"> <EasingColorKeyFrame KeyTime="0" Value="LightGray" /> </ColorAnimationUsingKeyFrames> <!-- border に TextBlock.Foreground を追加する必要がある ContentPresenter に Foreground がないため--> <ColorAnimationUsingKeyFrames Storyboard.TargetName="border" Storyboard.TargetProperty="(TextBlock.Foreground).(SolidColorBrush.Color)"> <EasingColorKeyFrame KeyTime="0" Value="Black" /> </ColorAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="Disabled"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="disabledRect" Storyboard.TargetProperty="(UIElement.Visibility)"> <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}" /> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> </VisualStateGroup> <VisualStateGroup x:Name="FocusStates"> <VisualState x:Name="Unfocused"/> <VisualState x:Name="Focused"> <Storyboard> <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="focusRectangle"> <EasingDoubleKeyFrame KeyTime="0" Value="1"/> </DoubleAnimationUsingKeyFrames> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <Border x:Name="border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" TextBlock.Foreground="{TemplateBinding Foreground}" CornerRadius="12"> <Grid x:Name="grid"> <ContentPresenter x:Name="contentPresenter" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" Margin="{TemplateBinding Padding}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" /> <Rectangle x:Name="focusRectangle" Stroke="{TemplateBinding Foreground}" Opacity="0" StrokeThickness="1" StrokeDashArray="2 2" Margin="4" RadiusX="12" RadiusY="12" /> </Grid> </Border> <Rectangle x:Name="disabledRect" Visibility="Collapsed" Fill="Black" Opacity="0.5" /> </Grid> </ControlTemplate> <Style x:Key="buttonStyle" TargetType="Button"> <Setter Property="Background" Value="White" /> <Setter Property="Foreground" Value="Blue" /> <Setter Property="BorderBrush" Value="Red" /> <Setter Property="BorderThickness" Value="3" /> <Setter Property="FontSize" Value="24" /> <Setter Property="Padding" Value="12" /> <Setter Property="Template" Value="{StaticResource buttonTemplate}" /> </Style> </Window.Resources> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="*" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Button Content="Disable center button" Grid.Column="0" Style='{StaticResource buttonStyle}' Click='OnButton1Click' HorizontalAlignment='Center' VerticalAlignment='Center' /> <Button x:Name='centerButton' Content='Center button' Grid.Column='1' Style='{StaticResource buttonStyle}' FontSize='48' Background='DarkGray' Foreground='Red' HorizontalAlignment='Center' VerticalAlignment='Center' /> <Button Content='Enable center button' Grid.Column='2' Style='{StaticResource buttonStyle}' Click='OnButton3Click' HorizontalAlignment='Center' VerticalAlignment='Center' /> </Grid> </Window>

この XAML は、既に説明したビジュアル状態の他にもアニメーションなどの数か所を変更しています。変更箇所を次に示します。

  • CommonStates の PointOver を MouseOrver に変更。
  • CommonStates の Pressed の Storybord 内のアニメーションを変更。
    ObjectAnimationUsingKeyFrame を ColorAnimationUsingKeyFrames へ変更。
    TargetProperty 添付プロパティを「(Background).(SolidColorBrush.Color)」表記へ変更。
    TargetProperty 添付プロパティを「(TextBlock.Foreground).(SolidColorBrush.Color)」表記へ変更(WPF XAML の ContentPresenter は Foreground プロパティを持たないため)。
    DiscreteObjectKeyFrame を EasingColorKeyFrame へ変更。
  • CommonStates の Disabled の Storyboard 内のアニメーションを変更。
    TargetProperty 添付プロパティを「(UIElement.Visibility)」 へ変更。
    DiscreteObjectKeyFrame の Value を「{x:Static Visibility.Visible}」へ変更。
  • ForcusedStates を ForcusStates に変更。
  • ForcusStates の Forcused の storyboard 内のアニメーションを変更。
    DoubleAnimation を DoubleAnimationUsingKeyFrames に変更。
    TargetProperty 添付プロパティを「(UIElement.Opacity)」表記に変更。
  • Border へ 「TextBlock.Foreground="{TemplateBinding Foreground}"」 要素を追加。
    WPF XAML の ContentPresenter が Foreground プロパティを持たないため。
  • 組み込みスタイルを変更

変更箇所を見れば、ビジュアル状態の差異による変更とアニメーションの変更であることを理解できることでしょう。ContentPresenter クラスに関しては、Foreground プロパティを WinRT XAML が持っており、WPF XAML が持たないことによる変更を加えています。この理由が、Border 要素に TextBlock.Forground 添付プロパティを追加した理由であり、Button の Content にテキストを設定した時に使われるのが TextBlock であることを利用して添付プロパティにしています。ボタンをクリックした時のイベント ハンドラーを MainWindow.xaml.cs より抜粋して示します。

private void OnButton1Click(object sender, RoutedEventArgs e) { centerButton.IsEnabled = false; } private void OnButton3Click(object sender, RoutedEventArgs e) { centerButton.IsEnabled = true; }

このコードは、WinRT XAML と同じになります。それでは、実行結果を示します。

スクリーン ショットを見れば、フォーカスを取得した場合に点線がボタン内に表示されていることに気が付くことでしょう。これが、ビジュアル状態として定義した Focused のアニメーションによる効果になります。このようなコントロール テンプレートは、理解できるまでは複雑に思えますから、書籍を参考にしながら色々と試して学習することをお勧めします。でも、全ての人がコントロール テンプレートを定義する必要があるかと言えば、カスタム コントロールを作成するなどの一部の人に限られることでしょう。でも、コントロール テンプレートの仕組みを知っていることは、とても大切なことです。

11.12(P571) generic.xaml の使用

本節では、Windows ストア アプリ プロジェクトに含まれるスタイル シートを説明しています。Visual Studio 2012 のプロジェクトでは、StandardStyle.xaml が含まれており、Visual Studio 2013 のプロジェクトには StandardStyle.xaml は含まれていません。StandrdStyle.xaml は generic.xaml から作成されており、Visual Studio 2013 のプロジェクトをビルド時に generic.xaml が組み込まれるようになっています。これらのスタイル シートが、どのような役目を持っているかを説明しています。

WPF XAML では、カスタム コントロールを作成する場合に generic.xaml というスタイル シートが必要になります。Visual Studio でカスタム コントロール テンプレートを使って新しいアイテムを追加すれば、プロジェクト内に Themes フォルダが作成されて、その中に Generic.xaml というスタイル シートが作成されます。従って、カスタム コントロールを作成する場合に必要になるスタイル シートであると理解していただければ結構です。

11.13(P571) テンプレートのパーツ

本節では、コントロール テンプレートがどのような構造になっているかという観点でコントロールが含む部品である構成要素をパーツとして説明しています。その過程で、OnApplyTemplate メソッドや GetTemplateChild メソッドなども説明しています。OnApplyTemplate メソッドは public メソッドですが、GetTemplateChild メソッドが protected メソッドである点に注意してください。つまり、GetTemplateChild メソッドでコントロールのパーツへアクセスするには、対象のコントロールを継承したクラスを作成して、作成したクラス内で GetTemplateChild メソッドを使用しなければならないからです。

書籍では、具体例として Slider コントロールに HorizontalTemplate と VerticalTemplate という名前を付けてください。という説明があり、Slider のコントロール テンプレートをカスタマイズした BareBonesSilder プロジェクトの説明になります。ここで知っておかないといけない事は、HorizontalTemplate と VerticalTemplate という名前をどこから入手したかということです。最初に思いつくのが、ドキュメントに記述されているのではないかということです。事実として、ドキュメントに記述されているものもあります。

WPF XAML の Slider には、HorizontalTemplate と VerticalTemplate という名前は定義されていませんので、BoreBonesSlider プロジェクトと同じ方法を使ったテンプレートの定義方法は使えません。この理由は、テンプレートのパーツの構成が異なるからです。プログラミング Windows の著者であるペゾルドは、BoreBonesSlider プロジェクトの着想を MSDN マガジンの「テンプレートを使用した WPF コントロールのカスタマイズ」という記事にあることが、書籍の中の注記に記述されています。この記事の中に、BareBonesProgressBar サンプルがあります。このサンプルは、プログレス バーのテンプレートをカスタマイズするというものですが、このサンプルを Visual Studio 2013 へ移植したものの実行結果を示します。

このサンプルのコードを理解することで、どのようにカスタマイズができるかを理解できることでしょう。

書籍では、BareBonesSlider プロジェクトに手を加えることでスライダーをバネにした SpringLoaderSlider の説明をしています。このサンプルも、MSDN マガジンの「テンプレートを使用した WPF コントロールのカスタマイズ」という記事に原点があります。従って、この記事の SpringLoadedScrollBar サンプルを Visual Studio 2013 へ移植したものの実行結果を示します(このサンプルは、ProgressBar をカスタマイズしています)。

書籍のサンプルと違う点は、スライダーの向きを縦方向にするテンプレートが含まれていない点になりますが、スライダー をバネ状にカスタマイズするという観点では同じものになりますから、コントロールのカスタマイズという観点では有益なものになることでしょう。

書籍では、SpeedMeterProgressBar プロジェクトを使ってスライダーと速度計(プログレス バー)を使うサンプルの説明をしています。このサンプルも、MSDN マガジンの「テンプレートを使用した WPF コントロールのカスタマイズ」という記事に原点があります。従って、この記事の SpeedMeterProgressBar サンプルを Visual Studio 2013 へ移植したものの実行結果を示します。

書籍にも記述がありますが、MSDN マガジンの「テンプレートを使用した WPF コントロールのカスタマイズ」という記事を原点に WinRT XAML へ移植しているので、もとの記事を読むことが役立つことでしょう。

この節の最初で説明しましたが、標準コントロールのスタイルやテンプレートを学習するには、どうしたら良いでしょうか。ドキュメントを探すのも 1つの手法ですが、全てのコントロールに対してスタイルやドキュメントが記述されているわけではありません。このような場合に行うとしたら、Blend for Visual Studio や Visual Studio を使ったテンプレートの編集機能を使用することをお勧めします。テンプレート編集をビジュアルに行うことができるので、ここでは Blend を使ったテンプレート編集の方法を説明します。最初に、Blend でプロジェクトを開きます。次にテンプレートを編集したいコントロールを選択して、コンテキスト メニューから[テンプレートの編集]-[コピーして編集]を選択します。この方法は、WinRT XAML も WPF XAML でも同じで���。

そうすると、ダイアログが表示されますので、名前と定義先を指定して「OK」ボタンをクリックします。定義先とは、作成するスタイルを定義するリソースの場所になります。アプリケーションとは、App.xaml を意味し、このドキュメントが現在編集している Window や Page になります。

スタイル リソースが作成されると、スタイルの編集画面に切り替わります。

編集画面では、大きくは次に示す 2つの作業を行います。

  • 状態パネル
    ビジュアル状態を定義するために使用します。ビジュアル状態の名前を知らなくても、状態パネルを使って指定して、アニメーションの自動記録などを使うことでタイムラインを自動生成することができます。
  • オブジェクトとタイムライン
    ドキュメント ツリーを開いていくことで、目的となるオブジェクトを編集したりすることができます。

このサンプルでは、書籍と同じように Slider コントロール(WPF XAML)のテンプレートを編集しています。参考までに作成された、スタイルとテンプレートを示します。

<Window.Resources> <SolidColorBrush x:Key="SliderThumb.Static.Foreground" Color="#FFE5E5E5"/> <SolidColorBrush x:Key="SliderThumb.MouseOver.Background" Color="#FFDCECFC"/> <SolidColorBrush x:Key="SliderThumb.MouseOver.Border" Color="#FF7Eb4EA"/> <SolidColorBrush x:Key="SliderThumb.Pressed.Background" Color="#FFDAECFC"/> <SolidColorBrush x:Key="SliderThumb.Pressed.Border" Color="#FF569DE5"/> <SolidColorBrush x:Key="SliderThumb.Disabled.Background" Color="#FFF0F0F0"/> <SolidColorBrush x:Key="SliderThumb.Disabled.Border" Color="#FFD9D9D9"/> <SolidColorBrush x:Key="SliderThumb.Static.Background" Color="#FFF0F0F0"/> <SolidColorBrush x:Key="SliderThumb.Static.Border" Color="#FFACACAC"/> <ControlTemplate x:Key="SliderThumbHorizontalTop" TargetType="{x:Type Thumb}"> <Grid HorizontalAlignment="Center" UseLayoutRounding="True" VerticalAlignment="Center"> <Path x:Name="grip" Data="M 0,6 C0,6 5.5,0 5.5,0 5.5,0 11,6 11,6 11,6 11,18 11,18 11,18 0,18 0,18 0,18 0,6 0,6 z" Fill="{StaticResource SliderThumb.Static.Background}" Stretch="Fill" SnapsToDevicePixels="True" Stroke="{StaticResource SliderThumb.Static.Border}" StrokeThickness="1" UseLayoutRounding="True" VerticalAlignment="Center"/> </Grid> <ControlTemplate.Triggers> <Trigger Property="IsMouseOver" Value="true"> <Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Background}"/> <Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Border}"/> </Trigger> <Trigger Property="IsDragging" Value="true"> <Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Background}"/> <Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Border}"/> </Trigger> <Trigger Property="IsEnabled" Value="false"> <Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Background}"/> <Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Border}"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> <ControlTemplate x:Key="SliderThumbHorizontalBottom" TargetType="{x:Type Thumb}"> <Grid HorizontalAlignment="Center" UseLayoutRounding="True" VerticalAlignment="Center"> <Path x:Name="grip" Data="M 0,12 C0,12 5.5,18 5.5,18 5.5,18 11,12 11,12 11,12 11,0 11,0 11,0 0,0 0,0 0,0 0,12 0,12 z" Fill="{StaticResource SliderThumb.Static.Background}" Stretch="Fill" SnapsToDevicePixels="True" Stroke="{StaticResource SliderThumb.Static.Border}" StrokeThickness="1" UseLayoutRounding="True" VerticalAlignment="Center"/> </Grid> <ControlTemplate.Triggers> <Trigger Property="IsMouseOver" Value="true"> <Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Background}"/> <Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Border}"/> </Trigger> <Trigger Property="IsDragging" Value="true"> <Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Background}"/> <Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Border}"/> </Trigger> <Trigger Property="IsEnabled" Value="false"> <Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Background}"/> <Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Border}"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> <SolidColorBrush x:Key="SliderThumb.Track.Border" Color="#FFD6D6D6"/> <SolidColorBrush x:Key="SliderThumb.Track.Background" Color="#FFE7EAEA"/> <Style x:Key="RepeatButtonTransparent" TargetType="{x:Type RepeatButton}"> <Setter Property="OverridesDefaultStyle" Value="true"/> <Setter Property="Background" Value="Transparent"/> <Setter Property="Focusable" Value="false"/> <Setter Property="IsTabStop" Value="false"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type RepeatButton}"> <Rectangle Fill="{TemplateBinding Background}" Height="{TemplateBinding Height}" Width="{TemplateBinding Width}"/> </ControlTemplate> </Setter.Value> </Setter> </Style> <ControlTemplate x:Key="SliderThumbHorizontalDefault" TargetType="{x:Type Thumb}"> <Grid HorizontalAlignment="Center" UseLayoutRounding="True" VerticalAlignment="Center"> <Path x:Name="grip" Data="M 0,0 C0,0 11,0 11,0 11,0 11,18 11,18 11,18 0,18 0,18 0,18 0,0 0,0 z" Fill="{StaticResource SliderThumb.Static.Background}" Stretch="Fill" SnapsToDevicePixels="True" Stroke="{StaticResource SliderThumb.Static.Border}" StrokeThickness="1" UseLayoutRounding="True" VerticalAlignment="Center"/> </Grid> <ControlTemplate.Triggers> <Trigger Property="IsMouseOver" Value="true"> <Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Background}"/> <Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Border}"/> </Trigger> <Trigger Property="IsDragging" Value="true"> <Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Background}"/> <Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Border}"/> </Trigger> <Trigger Property="IsEnabled" Value="false"> <Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Background}"/> <Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Border}"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> <ControlTemplate x:Key="SliderHorizontal" TargetType="{x:Type Slider}"> <Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto" MinHeight="{TemplateBinding MinHeight}"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <TickBar x:Name="TopTick" Fill="{TemplateBinding Foreground}" Height="4" Margin="0,0,0,2" Placement="Top" Grid.Row="0" Visibility="Collapsed"/> <TickBar x:Name="BottomTick" Fill="{TemplateBinding Foreground}" Height="4" Margin="0,2,0,0" Placement="Bottom" Grid.Row="2" Visibility="Collapsed"/> <Border x:Name="TrackBackground" BorderBrush="{StaticResource SliderThumb.Track.Border}" BorderThickness="1" Background="{StaticResource SliderThumb.Track.Background}" Height="4.0" Margin="5,0" Grid.Row="1" VerticalAlignment="center"> <Canvas Margin="-6,-1"> <Rectangle x:Name="PART_SelectionRange" Fill="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" Height="4.0" Visibility="Hidden"/> </Canvas> </Border> <Track x:Name="PART_Track" Grid.Row="1"> <Track.DecreaseRepeatButton> <RepeatButton Command="{x:Static Slider.DecreaseLarge}" Style='{StaticResource RepeatButtonTransparent}'/> </Track.DecreaseRepeatButton> <Track.IncreaseRepeatButton> <RepeatButton Command='{x:Static Slider.IncreaseLarge}' Style='{StaticResource RepeatButtonTransparent}'/> </Track.IncreaseRepeatButton> <Track.Thumb> <Thumb x:Name='Thumb' Focusable='False' Height='18' OverridesDefaultStyle='True' Template='{StaticResource SliderThumbHorizontalDefault}' VerticalAlignment='Center' Width='11'/> </Track.Thumb> </Track> </Grid> </Border> <ControlTemplate.Triggers> <Trigger Property='TickPlacement' Value='TopLeft'> <Setter Property='Visibility' TargetName='TopTick' Value='Visible'/> <Setter Property='Template' TargetName='Thumb' Value='{StaticResource SliderThumbHorizontalTop}'/> <Setter Property='Margin' TargetName='TrackBackground' Value='5,2,5,0'/> </Trigger> <Trigger Property='TickPlacement' Value='BottomRight'> <Setter Property='Visibility' TargetName='BottomTick' Value='Visible'/> <Setter Property='Template' TargetName='Thumb' Value='{StaticResource SliderThumbHorizontalBottom}'/> <Setter Property='Margin' TargetName='TrackBackground' Value='5,0,5,2'/> </Trigger> <Trigger Property='TickPlacement' Value='Both'> <Setter Property='Visibility' TargetName='TopTick' Value='Visible'/> <Setter Property='Visibility' TargetName='BottomTick' Value='Visible'/> </Trigger> <Trigger Property='IsSelectionRangeEnabled' Value='true'> <Setter Property='Visibility' TargetName='PART_SelectionRange' Value='Visible'/> </Trigger> <Trigger Property='IsKeyboardFocused' Value='true'> <Setter Property='Foreground' TargetName='Thumb' Value='Blue'/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> <ControlTemplate x:Key='SliderThumbVerticalLeft' TargetType='{x:Type Thumb}'> <Grid HorizontalAlignment='Center' UseLayoutRounding='True' VerticalAlignment='Center'> <Path x:Name='grip' Data='M 6,11 C6,11 0,5.5 0,5.5 0,5.5 6,0 6,0 6,0 18,0 18,0 18,0 18,11 18,11 18,11 6,11 6,11 z' Fill='{StaticResource SliderThumb.Static.Background}' Stretch='Fill' Stroke='{StaticResource SliderThumb.Static.Border}'/> </Grid> <ControlTemplate.Triggers> <Trigger Property='IsMouseOver' Value='true'> <Setter Property='Fill' TargetName='grip' Value='{StaticResource SliderThumb.MouseOver.Background}'/> <Setter Property='Stroke' TargetName='grip' Value='{StaticResource SliderThumb.MouseOver.Border}'/> </Trigger> <Trigger Property='IsDragging' Value='true'> <Setter Property='Fill' TargetName='grip' Value='{StaticResource SliderThumb.Pressed.Background}'/> <Setter Property='Stroke' TargetName='grip' Value='{StaticResource SliderThumb.Pressed.Border}'/> </Trigger> <Trigger Property='IsEnabled' Value='false'> <Setter Property='Fill' TargetName='grip' Value='{StaticResource SliderThumb.Disabled.Background}'/> <Setter Property='Stroke' TargetName='grip' Value='{StaticResource SliderThumb.Disabled.Border}'/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> <ControlTemplate x:Key='SliderThumbVerticalRight' TargetType='{x:Type Thumb}'> <Grid HorizontalAlignment='Center' UseLayoutRounding='True' VerticalAlignment='Center'> <Path x:Name='grip' Data='M 12,11 C12,11 18,5.5 18,5.5 18,5.5 12,0 12,0 12,0 0,0 0,0 0,0 0,11 0,11 0,11 12,11 12,11 z' Fill='{StaticResource SliderThumb.Static.Background}' Stretch='Fill' Stroke='{StaticResource SliderThumb.Static.Border}'/> </Grid> <ControlTemplate.Triggers> <Trigger Property='IsMouseOver' Value='true'> <Setter Property='Fill' TargetName='grip' Value='{StaticResource SliderThumb.MouseOver.Background}'/> <Setter Property='Stroke' TargetName='grip' Value='{StaticResource SliderThumb.MouseOver.Border}'/> </Trigger> <Trigger Property='IsDragging' Value='true'> <Setter Property='Fill' TargetName='grip' Value='{StaticResource SliderThumb.Pressed.Background}'/> <Setter Property='Stroke' TargetName='grip' Value='{StaticResource SliderThumb.Pressed.Border}'/> </Trigger> <Trigger Property='IsEnabled' Value='false'> <Setter Property='Fill' TargetName='grip' Value='{StaticResource SliderThumb.Disabled.Background}'/> <Setter Property='Stroke' TargetName='grip' Value='{StaticResource SliderThumb.Disabled.Border}'/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> <ControlTemplate x:Key='SliderThumbVerticalDefault' TargetType='{x:Type Thumb}'> <Grid HorizontalAlignment='Center' UseLayoutRounding='True' VerticalAlignment='Center'> <Path x:Name='grip' Data='M0.5,0.5 L18.5,0.5 18.5,11.5 0.5,11.5z' Fill='{StaticResource SliderThumb.Static.Background}' Stretch='Fill' Stroke='{StaticResource SliderThumb.Static.Border}'/> </Grid> <ControlTemplate.Triggers> <Trigger Property='IsMouseOver' Value='true'> <Setter Property='Fill' TargetName='grip' Value='{StaticResource SliderThumb.MouseOver.Background}'/> <Setter Property='Stroke' TargetName='grip' Value='{StaticResource SliderThumb.MouseOver.Border}'/> </Trigger> <Trigger Property='IsDragging' Value='true'> <Setter Property='Fill' TargetName='grip' Value='{StaticResource SliderThumb.Pressed.Background}'/> <Setter Property='Stroke' TargetName='grip' Value='{StaticResource SliderThumb.Pressed.Border}'/> </Trigger> <Trigger Property='IsEnabled' Value='false'> <Setter Property='Fill' TargetName='grip' Value='{StaticResource SliderThumb.Disabled.Background}'/> <Setter Property='Stroke' TargetName='grip' Value='{StaticResource SliderThumb.Disabled.Border}'/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> <ControlTemplate x:Key='SliderVertical' TargetType='{x:Type Slider}'> <Border x:Name='border' BorderBrush='{TemplateBinding BorderBrush}' BorderThickness='{TemplateBinding BorderThickness}' Background='{TemplateBinding Background}' SnapsToDevicePixels='True'> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width='Auto'/> <ColumnDefinition MinWidth='{TemplateBinding MinWidth}' Width='Auto'/> <ColumnDefinition Width='Auto'/> </Grid.ColumnDefinitions> <TickBar x:Name='TopTick' Grid.Column='0' Fill='{TemplateBinding Foreground}' Margin='0,0,2,0' Placement='Left' Visibility='Collapsed' Width='4'/> <TickBar x:Name='BottomTick' Grid.Column='2' Fill='{TemplateBinding Foreground}' Margin='2,0,0,0' Placement='Right' Visibility='Collapsed' Width='4'/> <Border x:Name='TrackBackground' BorderBrush='{StaticResource SliderThumb.Track.Border}' BorderThickness='1' Background='{StaticResource SliderThumb.Track.Background}' Grid.Column='1' HorizontalAlignment='center' Margin='0,5' Width='4.0'> <Canvas Margin='-1,-6'> <Rectangle x:Name='PART_SelectionRange' Fill='{DynamicResource {x:Static SystemColors.HighlightBrushKey}}' Visibility='Hidden' Width='4.0'/> </Canvas> </Border> <Track x:Name='PART_Track' Grid.Column='1'> <Track.DecreaseRepeatButton> <RepeatButton Command='{x:Static Slider.DecreaseLarge}' Style='{StaticResource RepeatButtonTransparent}'/> </Track.DecreaseRepeatButton> <Track.IncreaseRepeatButton> <RepeatButton Command='{x:Static Slider.IncreaseLarge}' Style='{StaticResource RepeatButtonTransparent}'/> </Track.IncreaseRepeatButton> <Track.Thumb> <Thumb x:Name='Thumb' Focusable='False' Height='11' OverridesDefaultStyle='True' Template='{StaticResource SliderThumbVerticalDefault}' VerticalAlignment='Top' Width='18'/> </Track.Thumb> </Track> </Grid> </Border> <ControlTemplate.Triggers> <Trigger Property='TickPlacement' Value='TopLeft'> <Setter Property='Visibility' TargetName='TopTick' Value='Visible'/> <Setter Property='Template' TargetName='Thumb' Value='{StaticResource SliderThumbVerticalLeft}'/> <Setter Property='Margin' TargetName='TrackBackground' Value='2,5,0,5'/> </Trigger> <Trigger Property='TickPlacement' Value='BottomRight'> <Setter Property='Visibility' TargetName='BottomTick' Value='Visible'/> <Setter Property='Template' TargetName='Thumb' Value='{StaticResource SliderThumbVerticalRight}'/> <Setter Property='Margin' TargetName='TrackBackground' Value='0,5,2,5'/> </Trigger> <Trigger Property='TickPlacement' Value='Both'> <Setter Property='Visibility' TargetName='TopTick' Value='Visible'/> <Setter Property='Visibility' TargetName='BottomTick' Value='Visible'/> </Trigger> <Trigger Property='IsSelectionRangeEnabled' Value='true'> <Setter Property='Visibility' TargetName='PART_SelectionRange' Value='Visible'/> </Trigger> <Trigger Property='IsKeyboardFocused' Value='true'> <Setter Property='Foreground' TargetName='Thumb' Value='Blue'/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> <Style x:Key='SliderStyle1' TargetType='{x:Type Slider}'> <Setter Property='Stylus.IsPressAndHoldEnabled' Value='false'/> <Setter Property='Background' Value='Transparent'/> <Setter Property='BorderBrush' Value='Transparent'/> <Setter Property='Foreground' Value='{StaticResource SliderThumb.Static.Foreground}'/> <Setter Property='Template' Value='{StaticResource SliderHorizontal}'/> <Style.Triggers> <Trigger Property='Orientation' Value='Vertical'> <Setter Property='Template' Value='{StaticResource SliderVertical}'/> </Trigger> </Style.Triggers> </Style> </Window.Resources>

このスタイルとコントロール テンプレートが膨大なことを気にしないですください。内容は多いですが、Blend を使うことでビジュアルに編集することが可能だからです。このように、ドキュメントに記述がなくてもツールを使うことで標準コントロールのスタイルとテンプレートの編集を行うことができるようになっています。これも、XAML 系 UI 技術の特徴になっています。

11.14(P580) カスタム コントロール

本節では、カスタム コントロールに適用するスタイルやテンプレートが Themes フォルダーの Generic.xaml というスタイル シートに記述されなければならないことを説明しています。このことを説明するために Petzold.ProgrammingWindows6.Chapter11 プロジェクトにカスタム コントロールを作るという説明になっています。それでは、Petzold.ProgrammingWindows6.Chapter11 プロジェクトの NewToggle.cs を示します。

using System; using System.Windows; using System.Windows.Controls; namespace Petzold.ProgrammingWindows6.Chapter11 { public class NewToggle : ContentControl { public event EventHandler IsCheckedChanged; Button uncheckButton, checkButton; static NewToggle() { CheckedContentProperty = DependencyProperty.Register("CheckedContent", typeof(object), typeof(NewToggle), new PropertyMetadata(null)); IsCheckedProperty = DependencyProperty.Register("IsChecked", typeof(bool), typeof(NewToggle), new PropertyMetadata(false, OnIsCheckedChanged)); } public NewToggle() { this.DefaultStyleKey = typeof(NewToggle); } public static DependencyProperty CheckedContentProperty { private set; get; } public static DependencyProperty IsCheckedProperty { private set; get; } public object CheckedContent { set { SetValue(CheckedContentProperty, value); } get { return GetValue(CheckedContentProperty); } } public bool IsChecked { set { SetValue(IsCheckedProperty, value); } get { return (bool)GetValue(IsCheckedProperty); } } // protected をpublic public override void OnApplyTemplate() { if (uncheckButton != null) uncheckButton.Click -= OnButtonClick; if (checkButton != null) checkButton.Click -= OnButtonClick; uncheckButton = GetTemplateChild("UncheckButton") as Button; checkButton = GetTemplateChild("CheckButton") as Button; if (uncheckButton != null) uncheckButton.Click += OnButtonClick; if (checkButton != null) checkButton.Click += OnButtonClick; base.OnApplyTemplate(); } void OnButtonClick(object sender, RoutedEventArgs args) { this.IsChecked = sender == checkButton; } static void OnIsCheckedChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) { (obj as NewToggle).OnIsCheckedChanged(EventArgs.Empty); } protected virtual void OnIsCheckedChanged(EventArgs args) { VisualStateManager.GoToState(this, this.IsChecked ? "Checked" : "Unchecked", true); if (IsCheckedChanged != null) IsCheckedChanged(this, args); } } }

このコードは、OnApplyTemplate メソッドのアクセシビリティを protected から public へ変更しただけになります。これは、WinRT XAML と WPF XAML で OnApplyTemplate メソッドのアクセシビリティが異なることが理由です。それでは、Themes フォルダーの Generic.xaml を示します。

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:Petzold.ProgrammingWindows6.Chapter11"> <Style TargetType="local:NewToggle"> <Setter Property="BorderBrush" Value="Black" /> <Setter Property="BorderThickness" Value="1" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="local:NewToggle"> <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CheckStates"> <VisualState x:Name="Unchecked" /> <VisualState x:Name="Checked"> <Storyboard> <ThicknessAnimationUsingKeyFrames Storyboard.TargetName="UncheckButton" Storyboard.TargetProperty="(Border.BorderThickness)"> <DiscreteThicknessKeyFrame KeyTime="0" Value="0" /> </ThicknessAnimationUsingKeyFrames> <ThicknessAnimationUsingKeyFrames Storyboard.TargetName="CheckButton" Storyboard.TargetProperty="(Border.BorderThickness)"> <DiscreteThicknessKeyFrame KeyTime="0" Value="8" /> </ThicknessAnimationUsingKeyFrames> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <UniformGrid Rows="1"> <Button Name="UncheckButton" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" FontSize="{TemplateBinding FontSize}" BorderBrush="Red" BorderThickness="8" HorizontalAlignment="Stretch" /> <!-- Content="{TemplateBinding CheckedContent}" --> <Button Name="CheckButton" Content="{Binding RelativeSource={RelativeSource AncestorType=local:NewToggle}, Path=CheckedContent}" ContentTemplate="{TemplateBinding ContentTemplate}" FontSize="{TemplateBinding FontSize}" BorderBrush="Green" BorderThickness="0" HorizontalAlignment="Stretch" /> </UniformGrid> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style> </ResourceDictionary>

このス��イル シートは、次に示す点以外は WinRT XAML と同じになります。

  • 組み込みスタイルを変更。
  • ObjectAnimationUsingKeyFrame を ThicknessAnimationUsingKeyFrames に変更。
    TargetProperty 添付プロパティを 「(Border.BorderThickness)」に変更。
  • local:UniformGrid を UniformGrid に変更。
  • Button の Content を「{Binding RelativeSource={RelativeSource AncestorType=local:NewToggle}, Path=CheckedContent}」に変更。
    WinRT XAML では、作成しているカスタム コントロールの依存関係プロパティを記述できます(CheckedContent)。が、WPF XAML は、このような省略記法が許可されていないので、RelativeSource を使った正式な記述になります。

今度は、NewToggle コントロールを使用する NewToggleDemo プロジェクトの MainWindow.xaml の抜粋を示します。

<Window ... xmlns:ch11="clr-namespace:Petzold.ProgrammingWindows6.Chapter11;assembly=Petzold.ProgrammingWindows6.Chapter11" ... > <Window.Resources> <Style TargetType="ch11:NewToggle"> <Setter Property="HorizontalAlignment" Value="Center" /> <Setter Property="VerticalAlignment" Value="Center" /> </Style> </Window.Resources> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <ch11:NewToggle Content="Don't do it!" CheckedContent="Let's go for it!" Grid.Column="0" Margin="20" FontSize="24" /> <ch11:NewToggle Grid.Column="1" Margin="20"> <ch11:NewToggle.Content> <Image Source="Images/MunchScream.jpg" /> </ch11:NewToggle.Content> <ch11:NewToggle.CheckedContent> <Image Source="Images/BotticelliVenus.jpg" /> </ch11:NewToggle.CheckedContent> </ch11:NewToggle> </Grid> </Window>

この XAML は、組み込みスタイルを除けば WinRT XAML と同じになります。それでは、実行結果を示します。

ここまでの説明で、コントロールのスタイルとテンプレートというものが、かなりの部分で WinRT XAML と WPF XAML で共通であることが理解できたことでしょう。標準コントロールが持つスタイルの定義そのものは、WinRT XAML と WPF XAML で同じものありますが、Slider コントロールのように異なる考え方で作成されているものもあります。この問題は、提供されるコントロール自体が想定されている利用方法自体が違うことに起因していると考えることができます。この記事で説明した Blend を使用したテンプレートの編集機能を使えば、利用するコントロールのテンプレート編集は容易になることでしょう。考え方は、書籍に記述されていますので、熟読をお願いします。この節の最後としては、ペゾルドの「テンプレートを使用した WPF コントロールのカスタマイズ」という記事に記載されていますが、コントロールのスタイルをダンプするツールが「Applications = Code + Markup」という書籍のサンプルに含まれていますから、このサンプルである DumpControlTemplate を Visual Studio 2013 へ移植したものをサンプルに含めていますので、自分で試してみてください。DumpControlTemplate の実行結果を示します。

11.15(P586) テンプレートとアイテム コンテナー

本節では、コレクションをバインディングするコントロールで Selector( WinRT XAML では SelectorItem)を継承するコントロールが持つアイテム コンテナーを説明しています。提供するクラス階層などは、WinRT XAML と WPF XAML で異なりますが、考え方は同じなので置き換えて考えることで書籍の説明は両方に当てはまります。それでは、アイテム コンテナー スタイルを指定する CustomListBoxItemStyle プロジェクトの MainWindow.xaml の抜粋を示します。

<Window ... xmlns:ch11="clr-namespace:Petzold.ProgrammingWindows6.Chapter11;assembly=Petzold.ProgrammingWindows6.Chapter11" ... > <Window.Resources> <ch11:NamedColor x:Key="namedColor" /> </Window.Resources> <Grid> <ListBox Name="lstbox" ItemsSource="{Binding Source={StaticResource namedColor}, Path=All}" Width="380"> <ListBox.ItemTemplate> <DataTemplate> ... </DataTemplate> </ListBox.ItemTemplate> <ListBox.ItemContainerStyle> <Style TargetType="ListBoxItem"> <Setter Property="Background" Value="Transparent" /> <!--<Setter Property="TabNavigation" Value="True" />--> <Setter Property="Padding" Value="8,10" /> <Setter Property="HorizontalContentAlignment" Value="Left" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="ListBoxItem"> <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="SelectionStates"> <VisualState x:Name="Unselected"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="(TextElement.FontStyle)"> <DiscreteObjectKeyFrame KeyTime="0"> <DiscreteObjectKeyFrame.Value> <FontStyle>Normal</FontStyle> </DiscreteObjectKeyFrame.Value> </DiscreteObjectKeyFrame> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="(TextElement.FontWeight)"> <DiscreteObjectKeyFrame KeyTime="0"> <DiscreteObjectKeyFrame.Value> <FontWeight>Normal</FontWeight> </DiscreteObjectKeyFrame.Value> </DiscreteObjectKeyFrame> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="Selected" /> <VisualState x:Name="SelectedUnfocused" /> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <Grid Background="Transparent"> <ContentPresenter x:Name="ContentPresenter" TextElement.FontStyle='Italic' TextElement.FontWeight='Bold' Content='{TemplateBinding Content}' ContentTemplate='{TemplateBinding ContentTemplate}' HorizontalAlignment='{TemplateBinding HorizontalContentAlignment}' VerticalAlignment='{TemplateBinding VerticalContentAlignment}' Margin='{TemplateBinding Padding}' /> </Grid> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style> </ListBox.ItemContainerStyle> </ListBox> <Grid.Background> <SolidColorBrush Color='{Binding ElementName=lstbox, Path=SelectedItem.Color}' /> </Grid.Background> </Grid> </Window>

この XAML は、次に示す点を除けば WinRT XAML と同じになります。

  • ListBox.ItemContainerStyle で TabNavigation プロパティを削除。
    WinRT XAML 固有のためです。
  • ビジュアル状態、SelectedDisabled、SelectedPointOrver、SelectedPressed を削除。
    WPF XAML に定義されていないためです。
  • ビジュアル状態 Unselected の Storyboard のアニメーションを変更。
    ObjectAnimationUsingKeyFrame の TargetProperty 添付プロパティ を「(TextElement.FontStyle)」と「(TextElement.FontWeight)」に変更。
    DiscreteObjectKeyFrame の Value 属性をプロパティ構文に変更(FontStyles、FontWeights 列挙で値を指定するため)。
  • ContentPresenter に TextElement.FontStyle属性とTextElement.FontWeight 属性を追加。
    WPF XAML の ContentPresenter が FontStyke と FontWeight プロパティをサポートしないためです。
    逆に WinRT XAML の ContentPresenter がサポートしているだけとも言えます。

記述は書籍と同じように省略していますが、DataTemplate は WinRT XAML と同じになります。もちろん、実行結果も同じになります。

書籍と「テンプレートを使用した WPF コントロールのカスタマイズ」という記事を熟読することで、3 つのテンプレートをより理解することができることでしょう。書籍にも記述されていますが、WPF XAML は XAML UI 技術のフルセットなどので WPF を正しく理解していれば、サブセットである WinRT XAML への応用や移植がし易くなりますので、特にテンプレートを正しく理解するようにしてください。

ここまで説明してきた違いを意識しながら、第11章を読むことで WPF にも書籍の内容を応用することができるようになることでしょう。もちろん、この記事だけで説明していることも理解して頂ければ、WinRT XAML と WPF XAML に役立つことでしょう。

EC-CUBE の Azure SQL Database プラグイン ~ 日本発 CMS とグローバルなクラウドのメリット融合

MSDN Blogs - Tue, 08/26/2014 - 21:33
こんにちは。 EC-CUBE 2.13.2 対応版の Microsoft Azure SQL Database プラグインの正式版が、遂にリリースされました。 これにより、DTU (Database Throughput Unit) による性能保証、Point in Time Restore (35 日以内の任意の時点に戻せる機能)、世界規模での Active Geo-Relication など、EC-Cube を使った よりクリティカルな運用が、PaaS (DBaaS) を使って実現可能です。 EC-Cube - Microsoft Azure SQL Database プラグイン http://www.ec-cube.net/products/detail.php?product_id=291 現在、Azure Website のギャラリーから EC-Cube を立ち上げた場合は MySQL (ClearDB) が設定されますが、ここに、このプラグインを当てて SQL Database を使用できます。 また、PostgreSQL や MySQL に依存した一部プラグインはまだ未対応とのことですが...(read more)

Lync 2013 for IPad/IPhone での機能追加について

MSDN Blogs - Tue, 08/26/2014 - 21:10

Lync サポートのワトソンです。

Lync モバイルでは続々と機能の追加が行われております。

最新の Lync 2013 for IPad のアップデートでは会議の際に
複数のユーザーのビデオストリームがみれる [ギャラリービュー] が追加
されております。

こちらの機能により、ミーテイングで発言が多い 4 人のビデオストリーム
が以下のように表示されます。

IPad 端末でのギャラリービュー機能とは別に Lync 2013 for IPhone
およびに Lync 2013 for IPad で以下の二つの機能も追加されております。

1. ロビーコントロール
ロビーで待っているユーザーを会議に参加させる事ができるようになりました。

2. 参加者のコントロール
参加者を発表者にきりかえたり、参加者にきりかえたりする操作が可能になりました。

今後のアップデートをお楽しみに

 

Sending email to a Team Room

MSDN Blogs - Tue, 08/26/2014 - 18:40

Here's a very cool way to use our new VS Online extensibility (that will be available in TFS V.Next) to enable sending an email to a Team Room.  Our new REST, OAuth and Service Hooks support can be used in countless creative ways.

http://blogs.msdn.com/b/slange/archive/2014/08/26/send-email-to-a-team-room-with-vso-service-hooks-and-zapier.aspx

Brian

 

Data-Driven Load Tests using Visual Studio Online and SQL Azure

MSDN Blogs - Tue, 08/26/2014 - 15:49

Editors Note:

While working in Australia I was blessed to work with some truly gifted technologists.  In the SQL space David Lean was the local legend with the (deserved) reputation of being THE SQL Performance Guru.

David has since left Microsoft but continue his cutting edge work with SQL Server and Application Tuning. 

Thanks for the great post on using SQL Azure and performance Testing David!

-Chuck

 

 

 

Data-Driven Load Tests using Visual Studio Online and SQL Azure

Almost everyone who IT Operations for a large company can tell you war stories about apps whose performance died within 18 mths of going live. Many don't even last 6 mths.

Nearly everyone in corporate IT can tell you war stories about some application whose performance died within 6 - 18 mths of going into production.

Why do they blow up?

More often than not, the root cause is inadequate stress testing, with inadequate data. Either not enough data, or data whose distribution didn't represent real world. Including errors.

So why don't we do more testing?

Often it is because of the cost. Consider the costs of H/W (just for load generation), Data Center Floor space, Insurance, Testing S/W, & people. It is easy to burn more than $1 mill just trying to prove a new system can scale to the needs of the business.

So we try to make do. Without those resources, design decisions are often made by a single developer based on timing loops on their desktop.

Benefits & problems of caching will rarely be seen if you only test with one user. (ie: the developer on their laptop). Same goes for inefficient database queries & poor architecture.

Without load, it is impossible to answer the hard questions like.

The Async/Await is great for I/O bound applications, but it adds overhead. Given that IIS's application pool is designed to handle blocking threads. Would I get better perf by merely increasing the IIS thread pool's "Max Concurrent" parameters?

If my Web Servers are suffering Thread Starvation due to the synchronous calls blocking on the database. Will rewriting them as Async improve the situation or merely exacerbate the issue by the RDBMS to divert memory to tracking even more user requests? Should I just increase the IIS “Max Concurrent …” values?

The good news is Microsoft has made that investment for us. For around $6 you can simulate 200 users (no wait time) smash your system for 10 mins.

Data-Driven Load Tests using Visual Studio Online

This article shows how to create Load/Stress Tests for both Web Sites & Web API controllers, with the potential to simulate 10’s of thousands of users hitting your solution. Allowing you to compare caching & other techniques in order to optimise the rendering of your site.

Why Data Driven?

In recent years ASP.NET MVC has grown in popularity. And with it, the use of dynamic routing. This has created a problem for testers. Simply recording your mouse & keystrokes into a static test & then replaying them, doesn’t work if your URLs change frequently.

If your Web Site dynamically generates its URL’s based on your data, ie: your product catalogue or recent news events, then you need a load test that can also dynamically generate valid URL’s to click on.

Fortunately Visual Studio’s Web Performance Tests & Load Testing makes this easy. The answer is Data Driven Web Performance Tests.

What if you don’t have access to a dozen or more idle servers you can use to run these performance tests? The answer is in the cloud. Visual Studio Online makes it possible to simulate 1,000’s of users hitting your web site. You can get it running in under 5 mins.

There are 4 common scenarios for Data driven testing.

1. Simulating URL’s that change based on the data in your system.

2. Filling out a form with different data for different users.

3. Calling a Web Service with different parameters.

4. Simulating an AJAX call.

=======================================

Scenario 1: Dynamic URL’s.

Use Case: The logic in your page generates a URL based on some internal data structure. Eg: In an E-Commerce site each Product you sell is likely to have its own URL. For CMS System, each new article may have a unique URL.

In this example we will look at the Horse Racing Industry. The Meetings page (below) shows all the Races. Each cell is a link to a Races Page. Each race only occurs once, so its URL contains the MeetingDate. So each new day a new set of racing links are created. Any test you build today using static URL’s will be broken tomorrow.

Picture 1. : Each cell in the table points to a race page.

One approach is to have your test always go to the Meeting page. Then run the javascript on that page to select a valid link. The disadvantage with this approach is you tie up your test agents with meeting page processing. Which reduces the number of clients you can simulate per agent.

Another approach is to pre-calculate all the valid links immediately prior to the test execution & put them in a data store. The Test Agent only needs to ask for a valid URL & send it to the server you are testing.

Part A: Setup your data.

We will need to create table similar to the one below.

Our Test only needs the URL column. But sometimes an ID column is handy for the clean-up task.

Most SQL DBA’s would use SQL Server Management Studio (SSMA), but you don’t need to install SQL Client tools. Visual Studio is just as powerful as I will demonstrate.

1. Start Visual Studio

2. Click menu: View => SQL Server Object Explorer

3. Right Click SQL Server node

4. Click Add SQL Server …

5. Enter login credentials.

6. You should now see a SQL Object Explorer tree.

7. Tip: I put my test data in an Azure Database.

a. It has the following benefits :-

i. Safer than opening a port thru the corporate firewall to expose an internal SQL Server containing the Test data database.

ii. Closer to the VSO Test agents. So less latency.

iii. Better upload speed than most Home / Small Office LAN’s.

iv. Cheap, only pay for the duration of the testing then delete it. < 17 cents per day.

b. To “remember” your connection strings just copy it from the Azure Portal.

8. Open a SQL Query Window. R.Click your SQL Database => New Query …

9. I prefer to create a Schema to hold all my load testing artifacts. Especially if they aren’t in a dedicated database.

CREATE SCHEMA TestData;

GO

CREATE TABLE TestData.RacePage (

ID INT NOT NULL IDENTITY(1,1)

, URL VARCHAR(100) NOT NULL

, CONSTRAINT PK_ID PRIMARY KEY CLUSTERED (ID)

);

GO

10. To simplify the load tests Setup & Clean-up Scripts, I prefer to create Stored Procedures. This keeps the logic out of my scripts & closer to the data in case I need to change anything.

-- ===< Procedure for Load Test’s Setup Script >===

CREATE PROCEDURE TestData.p_SetupRacePageDataTest

( @WebSite VARCHAR(30) = 'http://mysite.cloudapp.net')

AS

-- Swap to a new meeting date at 5pm Sydney. (or 6am AEDT)

DECLARE @MeetingDate DATE = DATEADD(HOUR, 4, SYSUTCDATETIME());

TRUNCATE TABLE TestData.RacePage;

INSERT INTO TestData.RacePage(URL)

SELECT @WebSite + '/race/' + CAST(M.MeetingDate AS CHAR(10))

+ '/' + CAST(M.TrackId AS VARCHAR(5))

+ '/' + CAST(R.RaceNumber AS VARCHAR(2)) AS URL

FROM Racing.Meeting AS M

JOIN Racing.Race AS R ON R.MeetingId = M.MeetingId

WHERE M.MeetingDate = @MeetingDate

AND R.RaceStatusId = 1; -- 1 = Open Races Enum

GO

-- ---< Check it works >---

EXEC TestData.p_SetupRacePageDataTest;

GO

SELECT TOP 20 * FROM TestData.RacePage;

GO

-- ===< Procedure for Load Test’s Clean-up Script >===

CREATE PROCEDURE TestData.p_CleanupRacePageDataTest AS

TRUNCATE TABLE TestData.RacePage;

GO

11. Run it

Part B: Connect the data to your Web Test.

12. Select Menu: File => New Project => Test =>Web Performance and Load Test Project

a. Even if you only work by yourself I suggest you add it to Source Control. It is so handy to be able to roll back any mistakes you make.

b. Personally I prefer to use VSO’s Team Foundation Server. For small teams it is free & great to have a central store where your code is compiled & deployed via Continuous Integration. However you will note from the picture below, Visual Studio also works fine if you prefer to use another Source control system like Subversion or GIT.

13. The new web test automatically opens a browser, ready to start recording your test. As we plan to get our URL’s from our database, we don’t need to do this. Just hit stop & create a blank test.

14. R.Click WebTest1.webtest & Rename it. eg: RacePage.webtest.

 

15. Add a Data Source to your WebTest. There are 3 ways to do this.

a. Via the Toolbar

b. Via the Context Menu

c. Via the property menu. (which you’ll see later)

16. This should start the “New Test Data Source Wizard”

a. Enter the name of your Data Source. Eg: TestDataInAzureDB & choose database.

b. Click New Connection …

c. Enter the Connection details for your Azure Database.

d. Choose the Table(s) you created previously.

e. Note: If you need to add more tables later, just R.Click your data source & click “Edit Data Source”

17. Your Test should look something like this

Part C: Using the Data.

18. .Add an Http Request that calls your Server
R.Click on your Web Test => Add Request.

19. It creates an “empty” link that points to localhost. We will replace it with the URL’s in our Test Data table.

a. Click the HTTP Request, “http://localhost/”

b. Hit F4 to open the Properties pane.

c. Select the Url attribute & click the down arrow

d. Expand your Data Source, select the column in the table that contains your URLs

e. Note: the “Add Data Source” link. This is the third way to add a data source.

20. .Your Test is now complete. It should look similar to this.

. Part D: Adding your Web Test to a Load test.

There is nothing special you need to do for a data driven test. I’ll just repeat the steps here for those new to the process.

21. Add a Load Test to your Project..

a. R.Click your Project, eg: VSODataTest

b. Click Add => Load Test…

22. You should see the Load Test Wizard Dialog

a. Tab: Scenario

i. Name: RacePage

ii. Think Time profile: <whatever you want>

b. Load Pattern & Test Mix Model: <whatever you want>

c. Test Mix: Add => RacePage test

d. Network Mix & Browser Mix: <whatever you want>

e. Counter Sets <whatever you want>

f. Run Settings: Load Test duration.

i. Set the duration time for as long as you want.

ii. At present the “Test Iteration” option is not supported in the cloud. You can only run Fixed Duration tests.

g. Details

i. Sampling Rate is recommended to be > 15 secs. The larger you make it the lower the monitoring overhead. Ensuring your test measurement doesn’t hinder your ability to run the test. For small duration tests with few users, sometimes 5 secs will give you a few more data point without hurting the tests.

ii. Validation level: I recommend: Low

23. Rename your LoadTest. I used RacePage.loadtest

24. Unfortunately when you run your tests in the cloud you lose the Network Isolation & some of the benefits of having your own dedicated, isolated, expensive, test environment. It is a little harder to monitor the performance monitor counters of the system under load. Due to security issues, the On-Premise approach of adding the Performance Counters to your test doesn’t work. Two popular workarounds are :-

a. Perfmon Logs
RDP to each of the Azure Roles in your Solution. Configure Performance Monitor to save its counters to a Log File. So you can examine them once the Load test completes.

b. Application Insights
If you have Visual Studio 2013 Update 2, you will notice an “Applications” node.

i. Configure your project to push info to VSO Application Insights.

ii. R.Click on Applications => Get Performance Data from Application Insights.

 

iii. Nominate the Servers you will track.

c. The advantage of doing this is that App Insights also captures diagnostic & trace info. So if you stress your solution to breaking point, you can retrospectively examine your internal state to find bottlenecks & bugs.

d. Another advantage is App Insights works well with Azure Load balancing. So if your solution starts to spin up more instances under load, App Insights will automatically capture their metrics too. (It may be possible to do this with Powershell & perfmon but much harder, especially if the instances are deleted before the load test finishes.)

e. A disadvantage is App Insights is designed to minimise its impact on a product solution. So it caches its metrics & uploads it in bursts. This means if your Load Test is shorter than 10 mins. You will probably not see any data at all.

f. Another Disadvantage is it requires your app to be enabled for App Insights & the endpoints to be visible. Given all the other troubleshooting & operational monitoring benefits it provides, I’d recommend installing it even if you aren’t using it for Load Tests.

Part E: Create your Load Test Setup Scripts.

Before your load test starts you may need to generate a new set of test data. Once finished you may need to remove it all, to ensure the load test is repeatable. We can do this with Setup & Clean-up Scripts

25. How you organise your project is a matter of personal preference. I like to create folders to group files by type. eg: Scripts, LoadTests, WebTests. But for large solution consider organising them by the type of Testing eg: Stress Tests, Integration Tests, Smoke Tests. Or maybe the functionality you are testing. eg: Ordering, User Accounts, Stock Management.

26. To place your scripts in a folder called TestScripts.

a. R.Click your project eg: VSODataTest

b. Click Add => New Folder

c. Name: TestScripts

d. R.Click The TestScripts Folder

i. Add => New Item…

ii. Search for Text.

iii. Select “Text File

e. Name: RacePageSetup.cmd

27. There are many ways you can execute TSQL from a batch file. Once of the simplest is the SQLCmd.exe command line app that ships as part of the SQL Server Client tools.
Edit the file RacePageSetup.cmd & add the following command.

SQLCMD -U <DbUsername>@<AzureServerName> -P <myPassword>
-S <AzureServerName>.database.windows.net -d <database>
-p -e -Q "EXEC
TestData.p_SetupRacePageDataTest"
>> RacePageSetup_Output.txt 2> RacePageSetup_Error.txt

a. Notes:

i. In your file, this command should be on one single line.

ii. If you have Windows Active Directory available use “–E” (Windows Auth) instead of using a SQL Username & Password in your file. Alternatively you could write a script that retrieved the connection info somehow.

iii. –Q means run a single command & then exit. As I use a Stored Proc this is usually sufficient. But you can also get it to run a TSQL file.

28. Tip: Check your script is OK. To do this, open a command prompt & try running your Setup.cmd job from there. It is much faster to troubleshoot now than wondering why your Load Test failed.

a. R.Click your Script => Open Command Prompt

b. Execute your script file RacePageSetup from the command prompt.

E:\!Blog\VSODataTest\VSODataTest\TestScripts>dir

Volume in drive E is Dev2_E

Volume Serial Number is XYZD-0123

Directory of E:\!Blog\VSODataTest\VSODataTest\TestScripts

26/05/2014 08:25 PM <DIR> .

26/05/2014 08:25 PM <DIR> ..

26/05/2014 07:04 PM 214 RacePageCleanup.cmd

26/05/2014 07:04 PM 210 RacePageSetup.cmd

2 File(s) 424 bytes

2 Dir(s) 6,212,550,656 bytes free

E:\!Blog\VSODataTest\VSODataTest\TestScripts>RacePageSetup

E:\!Blog\VSODataTest\VSODataTest\TestScripts>´┐SQLCMD -U ….

c. Unfortunately you may notice an error. If you look at the RacePageSetup_Error.txt file, you will see an error message. “'SQLCMD' is not recognized as an internal or external command, operable program or batch file.” It is misleading, that is not the problem. Look closer at the DOS command output. The first command in your file died. It has 3 weird non-printable characters at the front “´. This is what happens when you save your .CMD files as “Unicode (UTF-8 with signature) – Codepage 65001.” Which is what Visual Studio uses by default. Those characters are the signature.

d. To fix this, Re-save the file as Unicode (UTF-8 without signature) – Codepage 65001

i. Menu: File => Save <filename.cmd> As …

ii. Select the Dropdown on the Save button, Save with Encoding …

iii. Set Encoding: Unicode (UTF-8 without signature) – Codepage 65001.

1. NB: I’ve not tried this with non-English Windows. You may need to open the file with a Binary editor & see what other formats are valid for your language setting.

iv. Try running it again. If you have no scripting errors it should work now.

29. Click your RacePageSetup.cmd file.

a. Hit F4, to open the Properties pane.

b. Set the “Copy to Output Directory” attribute to “Copy if newer

30. Repeat the above steps to create your Cleanup Script

31. Next configure your test parameters to use your Scripts

a. Double Click Local.testsettings.

b. Select tab: Setup and Cleanup Scripts

i. Point the “Setup Script” path to your Setup script.

Part F: Checking your work, locally

Do a quick “sanity check” & run it locally to fix any mistakes. If your test doesn’t run locally it will not run in the cloud. Not only will your catch config & scripting errors earlier, but this give you the ability to check each of the rows in your generated data. Perhaps finding invalid combinations, NULLs, divide by zero issues &/or other error conditions that you had not intended to test.

32. While still in the Test Settings dialog.

a. Click the Web Test Tab.

b. Select “One run per data source row

33. Open your Load test & click “Run Load Test

. Part G: Running it in the cloud.

While you can use your existing TestSettings file. I prefer to create a new one, as it makes it easier to swap back & forward between the two. The Local test is good as some problems are obvious even with a tiny number of users.

34. In Solution Explorer, R.Click the “Solution Items” folder => Add => New Item…

35. Create a new Test Settings file named Cloud.testsettings.

36. Open the Test Settings Dialog

37. Tab: General

a. Name: Cloud

b. Select “Run Tests using Visual Studio Online
That’s the real magic to running your tests in the cloud.

38. Tab: Setup and Clean-up scripts.

a. At I write this the SQL Setup & clean-up scripts will not work in the cloud. The SQLCMD app is not installed on the Test Agents. I expect this to change soon. So for now, leave this blank & run them manually.

39. Tab: Additional Settings. Run test in 64 bit process on a 64 bit machine.
Clearly this is optional but the default is 32 bit. So I change it

a. Note: the other tabs are not applicable in the cloud at this time.

40. Tell Visual Studio to start any load tests using the Cloud.Testsettings file.

a. R.Click the Cloud.testsettings file. => Select Active Load and Web Test Settings

41. That’s it. Click Run Load Tests & you are done.

a. Tip: The picture above might look like the Local.testsettings would run. At present VS gives you no indication which test settings file is active. I’m hoping this will change in the future. Prior to running any load test I recommend checking the context menu of the relevant testsettings file to ensure it has the little tick next to “Active Load and Web Test Settings”. Thus avoiding the frustration of running the wrong overnight test.

Scenario 2: Using Data to fill out Form fields.

The goal here is to have your test simulate 1,000’s of users filling out your web forms with data for your Web server to process. Useful to ensure your backend can handle the millions of new orders, customer registrations, service requests or wherever it is you do.

Part A: Record a Web Test that has fields that need to be populated with data.

1. Within a Web Performance and Load Test Project.

2. R.Click a Project (eg: VSODataTest) => Add => Web Performance Test …

3. Your default browser will open (I’ve found Internet Explorer to be the best for recording Web Tests)

4. Click Record

5. Click on the pages that will form your Web Test. Shown below is the page with the fields I’d like the test to populate.

6. When you are done, click Stop. Delete any of the links you do not need for your test.

7. Below you can see the Form Post Parameters as I filled them out when recording. This are the fields we will link to our data source.

8. Rename the webtest from WebTest1 to something meaningful. (eg: NewUser.webtest)

Part B: Connecting to the data.

In Scenario 1, we connected to the data first & then build the test. Here we do it the other way around. Just to show that the order doesn’t matter.

9. Create a table with Test data. (if you haven’t got one already.) Usually the web page form will persist the data entered by the user into a specific table. So I start by copying the definition of that table & then add/remove any extra columns as required.

Sample Table

CREATE TABLE TestData.NewUser (

NewUserId INT NOT NULL IDENTITY (1, 1),

FirstName NVARCHAR (30) NOT NULL,

MiddleName NVARCHAR (30) NULL,

LastName NVARCHAR (40) NOT NULL,

BirthDate DATE NULL,

UserName NVARCHAR (25) NULL,

Email NVARCHAR (50) NOT NULL,

Email2 NVARCHAR (50) NULL,

Phone NVARCHAR (14) NULL,

FlatNo NVARCHAR (12) NULL,

StreetNo NVARCHAR (12) NULL,

Street NVARCHAR (200) NULL,

StreetType CHAR (4) NULL,

Suburb NVARCHAR (25) NULL,

[State] NVARCHAR (3) NULL,

PostalCode VARCHAR (4) NULL,

CountryCode CHAR (2) NULL DEFAULT 'AU',

ReferralId SMALLINT NULL DEFAULT '0',

ReferralOther NVARCHAR (50) NULL,

CONSTRAINT PK_NewUser PRIMARY KEY CLUSTERED (NewUserId)

);

When complete it may look something like this.

Unlike the Scenario 1: RacePage example, this data is not transient & not dependent on any the values in another table. So it is possible to load it once with SQL’s Bulkcopy or SSIS then leave it. As creating & loading random data into SQL is well documented elsewhere, I will not explain it here.

At the end of a load test, a clean-up script would “somehow” need to reverse any changes. The most common approaches are:-

A. Completely reset the entire database after each test.

i. Backup the database prior to the test, then Restore it when finished. OK for big tests but otherwise time consuming & impacts the work of others.

B. Reverse just the data you have changed.

i. Use a SQL Merge Statement to compare the “test data” table with the rows in the target table & delete them. Very quick & simple, especially if the Web Test only effects one table.

ii. For Unit Tests you can sometimes use a transaction & roll it back when finished. But for stress testing it is not recommended. You are likely to create dead locks & artificial IO bottlenecks.

C. Put an unlikely value in a field of your Test data eg: Middle name = “Test Data”. So you can find & remove those rows quickly without impacting data other developers might be using.

D. If the Target tables contain a set of poor man’s audit columns (eg: CreatedDate, CreatedBy, ModifiedDate), you can remove the rows based on the time they were created. Note: Please do not view this as a recommendation to clutter your DB Schema with “CreatedBy” columns. It is a bad practise that hurts performance. Yet many developers still do it.

10. Add a Data Source (As outlined in Scenario 1)

11. Map each field in your form a column in your Data Source table or view.

12. The rest is the same as Scenario 1.

a. Add this Web test to a Load Test.

b. Test all is OK locally.

c. Run the big test from VSOnline.

Scenario 3: Data-Driven Web Service tests.

The goal is to load your WebAPI2 controller &/or other RESTful servers.

The increase in Mobile solutions & Single-Page Applications (SPA’s) has make the creation of RESTfull services much more common. Testing is very similar to Scenario 1. So I will only highlight the differences here. The most significant difference is the way the data is bound to the query string.

Part A: Create a new Web Test & attach your Data Source

For instructions see Scenario 1, Part B.

Note: If you already have a Web Test Project. You can add another Web Test as follows.

1. Right-Click your Web Performance and Load Test Project.

2. Add => Web Performance Test …

3. It will automatically start the Web Test Recorder in your browser. Hit Stop. You don’t need to record anything.

4. You should now see the Web Test Editor.
Consider renaming it to something more descriptive.

5. Add a Data Source. (See Scenario 1. Part B)

Part B: Connecting to the data.

6. R.Click the test => Add Web Service Request

7. Change the URL from the default http://localhost to your test Service. Hit F4 to view the Properties pane, tweak the properties as needed. Consider changing; Response Time Goal, Think Time & Timeout.

8. Select the “String Body” node. Click the “String Body Property & click the “…” button.

9. This is the confusing bit. Unlike the earlier examples where a property that says “supports data binding” give you some UI to link to your data source. Here you get nothing but an empty window.

10. The trick is to use parameter substitution to create whatever HTTP string your service expects. The syntax for the data bound parameter is {{DataSourceName.TableName.ColumnName}}

11. For example. If your web server expects a SOAP request in the following format.

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Body>
        <PlaceBet xmlns="http://tempuri.org/">
            <RaceID>int</RaceID>
            <Horse>string</Horse>
            <Amount>int</Amount>
        </CheckStatus>
    </soap:Body>
</soap:Envelope>

12. With parameters it would look like this.

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Body>
        <PlaceBet xmlns="http://tempuri.org/">
            <RaceID>{{MyDataSourceName.TestBet.RaceID}}</RaceID>
            <Horse>{{MyDataSourceName.TestBetDetail.Horse}}</Horse>
            <Amount>{{MyDataSourceName.TestBetDetail.Amount}}</Amount>
        </CheckStatus>
    </soap:Body>
</soap:Envelope>

13. Tip. The above format works well for SOAP, AJAX & similar calls. But it assumes a fairly simple structure where each item can be mapped to a column. And each item only occurs once. Eg: The WinOrPlaceSelections array node below only contains 1 item.

{

"BetType":1,"RaceNumber":11,"RaceId":41397,"TrackId":589

,"MeetingDate":"2014-08-07T00:00:00",

"WinOrPlaceSelections":[

{"Amount":"2","RunnerNo":8,"Odd":0.00,"BetProductId":3}

]

,"AccountId":1017}

This gets harder if you want to pass an array of values.

{

"BetType":1,"RaceNumber":8,"RaceId":41151,"TrackId":566,"MeetingDate":"2014-08-07T00:00:00"

,"WinOrPlaceSelections":[

{"Amount":"1.5","RunnerNo":6,"Odd":21.00,"BetProductId":79}

,{"Amount":"3.5","RunnerNo":2,"Odd":4.30,"BetProductId":1}

,{"Amount":"1.5","RunnerNo":7,"Odd":7.80,"BetProductId":151}

,{"Amount":"2.5","RunnerNo":6,"Odd":4.50,"BetProductId":1}

,{"Amount":"1","RunnerNo":6,"Odd":12.50,"BetProductId":3}

]

,"AccountId":1013}

While you could create a parameter that contains all the items in array. I’ve found it much easier to generate the entire JSON string in a single column of my database test table. And pass the whole lot in one parameter.

Scenario 4: Data-Driven AJAX tests.

Use Case: Single Page Applications (SPA’s), Knockout, AngularJS are some of the many common apps that make extensive use of AJAX calls. Regardless of what javascript framework or library you use eventually it will result in an HTTPQueryString being sent to your Web Server.

If you are running Visual Studio Test On-Premise or via your own Azure IAAS machines. You could automate the User Interface to run your javascript, which generates & sends the HttpQueryString. At present Visual Studio Online does not support CodedUI Tests. They are really designed for UI testing & don’t scale very well. You could also use other web test frameworks; ie: Selenium, Jasmine, PhantomJS.

Like Scenario 1, for stress testing you may find it undesirable to automate the client code just so you can generate a load on your servers. Often all you really need is a valid HTTPQueryString.

So process is identical to Scenario 3, except that you record your interactions with your web site. Once complete:-

1. Click on the URL’s which contain the AJAX calls.

2. Click on the “String Body” node

3. Open the Properties pane & select “…”

4. Update the String body to a Parameterised Query.

Known Limitations & workarounds

Online Testing helps to reduce gap between the little guy & the well-resourced enterprise dept. It is still a work in progress as MS test suite is quite broad & at the time of posting this article there are many things that the On-premise product offers that the Cloud version does not.  Microsoft’s Cloud offering has new features added every month. By the time you read this, these feature gaps may no longer exist.

For instance the Startup & CleanUp Scripts in your Online Load tests can’t call SQL Server

Workaround: Run them manually. This may be resolved soon

Can’t run Javascript

This is annoying. But reflect on what you are trying to achieve, there may be alternatives.

1. If your focus is exercising the client code (Javascript), it is likely you are really running Unit Tests, Cross browser & similar UI functionality tests. It may be just as effective to run these tests locally on a single client machine. The goal of multiple clients is to put a load on the server, or find concurrency issues; locking or race conditions.

2. As your client code is not run on the tests, it is possible form a small number of test agents to simulate many more client interactions. Especially if you generate the client response before the test starts & simulate sending it to the server.

Catch All Workaround

Visual Studio Online tests are powerful, but Visual Studio Test Manager can do even more. So if your multi-million dollar, dedicated test data-center is unavailable. Consider using the cloud by creating Azure IAAS VM instances. Install Windows & configure one as a Test Agent & the other as Test controller.

 

About the Author

David Lean is LONG time Microsoft veteran (1990-2009) that has recently retired.  He is currently focusing on his passions share/trading applications and assisting MS Customers & Partners with SQL Server related projects & performance tuning.

Porting a Windows Store App using HTML to Cordova

MSDN Blogs - Tue, 08/26/2014 - 14:46

Visual Studio recently released a preview for Multi-Device Hybrid Apps, that allows you to create Cordova apps in Visual Studio. Cordova is a cross-platform API and build toolset that provides access to native device APIs using HTML, CSS, and JavaScript. If you've already created a Windows Store app using HTML and JavaScript, you can port your app to Android and iOS by using Cordova. The easiest way to move the project to Cordova is to create a Multi-Device Hybrid App in Visual Studio using the open source version of WinJS (Windows Library for JavaScript).

Out of the box, the Multi-Device Hybrid Apps extension for Visual Studio includes only the Blank template. I took one of the more popular Windows Store templates, the Navigation App template, and ported it to Cordova. This template is available here. In this post, I thought I'd share what I learned in that process.

Before going through the porting process, you can evaluate your app for the likely difficulty of making it work in Cordova. Here are some of the main considerations:

  • Are there a lot of calls to Windows Runtime APIs? Cordova in VS supports the WinJS APIs, but native Windows Runtime APIs won't work in WinJS. For app lifecycle code and a few other common events, Cordova has APIs that you can use instead. For other native code, you may need to use a Cordova plugin to replace the native APIs, and code your app using the plugin's interface (JavaScript APIs).
  • If you need to use a Cordova plugin for access to native APIs (for example, Geolocation or Camera APIs), check whether the feature is supported in a core plugin or a third-party plugin. Core plugins typically support all the most common target platforms; in third-party plugins, platform support varies. If plugin support is not already available for the native feature, work will be required to create a custom plugin (or to extend an existing plugin) before your app will work in Cordova. Creating a custom plugin will involve writing native code for the platform(s) that you are going to support.
  • Are you using any third-party frameworks besides WinJS? Some frameworks may have incompatibilities with specific platforms or with Cordova.

The main steps involved in porting your app to Cordova:

  1. Create your project using a Multi-Device Hybrid App sample app that uses WinJS.
  2. Open it in VS, manually copy over your code, and get rid of any sample code that you don't need.
  3. Update the app lifecycle code to use Cordova events.
  4. Rewrite code that requires the use of a plugin.
  5. Test the CSS in the various emulators. Use the merges folder for platform-specific CSS, if necessary.
  6. Update images in platform resource files.

1. Create your project using a Multi-Device Hybrid App sample

Instead of using the Blank template included with Cordova, start with one of these sample apps; the apps listed here simplify the setup of the open source WinJS. A custom PowerShell script in the project file will automatically download and include WinJS when you build the project.

  • Cordova Navigation Template (WinJS). This is a port of the Windows Store Navigation App template, and provides a simple multi-page app with page animations and Back button support. It includes the Windows Store navigator.js file.
  • ToDoList sample using WinJS. This sample provides local storage using HTML5 Web Storage, cloud-storage using Azure Mobile Services, and geolocation using Bing Maps. Note that this sample uses TypeScript out of the box.
2. Manually copy your HTML, JavaScript, and CSS code, and get rid of sample code you don't need

No shortcuts here, but it's not hard for smaller apps. Cordova uses an index.html file instead of default.html. If you use the out-of-the-box Cordova project structure, you will naturally need to update script and internal URI references;  for example, in calls to WinJS.Navigation.navigate.


3. Update the app lifecycle code

The app lifecycle code in a Windows Store app likely includes one or more calls to Windows Runtime APIs. You need to replace these with Cordova APIs, such the deviceready event handler. Here is an example of app lifecycle code from the Cordova Navigation Template. This code eliminates the need to call the Windows.ApplicationModel.Activation API.


(function () {
    "use strict";

    var app = WinJS.Application;
    var nav = WinJS.Navigation;
    var sched = WinJS.Utilities.Scheduler;
    var ui = WinJS.UI;

    document.addEventListener("deviceready", onReady, false);
    document.addEventListener("resume", onResume, false);

    function onReady() {
        // Handle the deviceready event.
        initialize();
    }
    function onResume() {
        // Handle the resume event
        initialize();
    }

    function initialize() {

        nav.history = app.sessionState.history || {};
        nav.history.current.initialPlaceholder = true;

        // Optimize the load of the application and while the splash screen is shown,
        // execute high priority scheduled work.
        ui.disableAnimations();
        var p = ui.processAll().then(function () {
            return nav.navigate(nav.location || Application.navigator.home, nav.state);
        }).then(function () {
            return sched.requestDrain(sched.Priority.aboveNormal + 1);
        }).then(function () {
            ui.enableAnimations();
        });

    }

})();


4. Rewrite code that requires use of a plugin

If your app requires extensive use of one or more plugins, this step will likely involve the most work. If it requires only plugins that already work on all target platforms, especially the core plugins, comparatively less work will be required.


To support certain types of changes you made to the package.manifest file in the new app (before you ported it), you may have to use a plugin.
Cordova provides some handy APIs for a few events such as backbutton. If you can use these events instead of native APIs, you don't need to use a plugin. For more info, see Events.


5. Test and update the CSS

You're in the web developer world now! You will need to test your app on the different platforms and deal with browser differences in CSS implementations. Fortunately, WinJS should handle most of this, but there are exceptions. For example, Webkit-based browsers (Android, iOS) don't currently support the CSS3 grid layout, so you may need to use a flexbox in your app instead.


The Ripple Emulator will provide quick and easy testing of layout and CSS on Android and iOS. But, of course, to really verify your app you will need to do testing on platform emulators and devices.


The best practice for handling differences in display size (and orientation changes) is to use @media rules. For example, the following CSS applies to display sizes <500 px in width. Here, you override margin values for the .fragment header CSS selector.


@media (max-width:499px) {
    .fragment header[role=banner] {
        margin-left: 15px;
        margin-right: 30px;
    }
}


If necessary, use the merges folder to provide platform-specific CSS values. Cordova recommends using an overrides.css file for this purpose. When you use overrides, you should include an empty overrides.css in the project's css folder.


WinJS provides ui-dark.css and ui-light.css as style templates. You will need to decide which one provides the look you want in your app and whether you want the app to look the same on all platforms. If not, you will need to decide how much extra effort you want to invest to make the app look like a native app on all target platforms.


6. Update images in platform resource files

Android and iOS include device-specific files for the splashscreen and icons. The sample apps include these files, but the art will need to be updated for your app.


Finally -- Test, package, and publish


Packaging and publishing is platform-specific. For more info, see the documentation.


VS for Multi-Device Hybrid Apps doesn't currently support debugging Windows Phone targets. This is because Cordova (at present) generates a native Silverlight WebView app for Windows Phone (unlike Windows, where Cordova generates a native Windows Store app). So, if you're porting from a Windows Store app, you may choose to test, package, and publish for Windows Phone using your native Windows Store project (requires Windows 8.1 for phone support).

Send Email to a Team Room with VSO Service Hooks and Zapier

MSDN Blogs - Tue, 08/26/2014 - 14:29

If you haven’t read up on some of the great work the VSO team is doing around Service Hooks, you should do so now.  It’s a great, easily-consumable, extensible way to integrate VSO with other tools you may use.  Service Hooks can also make VSO even easier to leverage in your organization.

In this post, I’m going to address a question I get from time to time: “The Team Rooms are great.  Can I send an email to VSO and have it show up in a Team Room?”  With a service hook, sure!

To do this, I’m going to use Zapier, a free service that allows you to build triggered actions between systems (called “zaps”).  They just so happen to have a service hook into VSO, and an email parsing service that they provide themselves (they give you an email address to use, and it parses emails received at that address to perform in subsequent actions).

Here’s what I did:

I head over to Zapier and sign up for an account.  They have several plans, including a free one.

I select to create a new Zap

When asked to choose a trigger or action, I select the Zapier Email Parser

Note that it ask me to also set up a parser mailbox at http://parser.zapier.com.  I went over there real quick and set one up:

After creating a parser account, I set up a parser mailbox (this is effectively an email address that captures and parses email messages).

You’ll get an screen like this, with an email address for you to send to.

Send an email to the cryptic email address on  your screen, and soon after it will capture the email and take you through the remaining steps to set up a mailbox parser.  This will allow you to later customize the display of the email message in the VSO Team Room.

Once that’s done, on the page where you’re setting up your “Zap”, select “New Email” as the action under the “Zapier Email Parser”.

On the right side (“..Do This.”), select Visual Studio Online, and “Send Team Room Message” as the corresponding action.  Your “Zap” should look like this:

I click the “Continue” button, which takes me to step 2, where I’m asked to connect to my Zapier Email Parser account, which I do.  I click “Test this Account” verify.

After clicking “Continue” again, I’m taken to step 3, where I specify my VSO account.

I select the account I want to use, authenticate to it and authorize Zapier to access it.  I can also give it a friendly name.  When I’m done, it looks like this (in my example), after testing it.

I click “Continue” again, and am taken to step 4 where I specify triggers for the email parser.  I simply choose the mailbox that I set up earlier.

Note that I can add custom filters if I want.  For this example (all I’m using this mailbox for is VSO Team Room messages), I’m not.

I click “Continue” to go to step 5.  On this step, I specify the Team Room that I want my emails to be pushed into (in my case, I choose “Awesome Calculator Team Room”), and set up the message that will be posted (based on the fields that you set up when you created  your Zapier Email Parser mailbox.  Here’s what mine looks like:

Lastly, I click “Continue” one more time to go to step 6.  This step lets me test my Zap.

Let’s test it!  I click on the “Test Zapier Email Parser trigger” and choose the sample data set to use (it will be the content from the test email you sent earlier to set up your mailbox). 

I head over to the VSO Team Room.  And voila! There it is!

That’s really it!  Now any time someone sends an email to that garbled email address set up via the Zapier Email Parser, the email will be parsed and posted to the Team Room. 

A couple suggestions:

  • Keep the email somewhat cryptic so no outsiders can guess it (the Parser will let you customize it).
  • Use a Welcome Page on your VSO project site to tell team members what the address is.

Now to be fair, there are other services that can help you respond to email events – the one depicted here was simply a straightforward one for me to figure out.  This is a simple example – I’d love to hear what extra fun people are having with service hooks.

Hope this helps!

HCK QFE 11 for Windows 8.1 now available

MSDN Blogs - Tue, 08/26/2014 - 14:28

For information about QFE updates, see Windows Hardware Certification Kit QFE Updates.

To get the latest QFEs for the Windows HCK, run HCKSetup.exe. The Windows HCK download includes all previous QFE updates.

Learn what's in the QFE

Download and install HCK to get the QFE

Download the QFE now

Note: Before applying the QFE, close all active HCK Studio sessions. Applying this QFE might affect in-progress submissions, so please complete any submissions before applying the QFE. After installing this QFE, you'll need to regenerate any affected submission that was generated before the QFE was installed.

Ny bog: Dynamics C5 2014 - Varekartotek og lager

MSDN Blogs - Tue, 08/26/2014 - 13:51

Logos Consult har netop lagt en ny bog på deres netbutik Dynamics C5 2014 – Varekartotek og lager.

Manualen giver indblik i grundlæggende lagerstyring, salg, priser, lager og ressourcer i Microssoft Dynamics C5 2014. Bogen er på 221 sider og er på dansk.

Bestil bogen her.

Med venlig hilsen

Dynamics Teamet

STORT TILLYKKE!

MSDN Blogs - Tue, 08/26/2014 - 13:07

Kære Partnere,

Dynamics teamet er stolte over at kunne ønske hele 3 danske partnere tillykke med kvalificeringen i den seneste ”Customer Adds incentive programme", som kørte hele sidste år.

STORT TILLYKKE til:

-         Navi Partners
-         Inventio.IT
-         Cornator

Vi sætter enormt stor pris på den indsats som alle Dynamics partnere i Danmark yder hver dag i jagten på licenssalg og nye customer adds. Derfor værdsætter vi det også, når I deltager i disse løbende salgskonkurrencer.

Vi ser frem til et super godt og dynamisk FY15. 

Med venlig hilsen

Dynamics Teamet

Gearing Up For a Career in Tech: Why Justin Wunder Became a Microsoft Student Partner

MSDN Blogs - Tue, 08/26/2014 - 12:54

This post is part of an ongoing series on preparing for a career in technology by the Microsoft Student Partner Program. For more career advice and to learn how you can get a jumpstart at your local university follow @MS_Student on Twitter and share your questions using the #WhyMSP hashtag.

Justin Wunder (@donchawunder) is a former MSP and Senior at the Louisiana Tech University and majoring in Computer Information Systems. We sat down to get some insight into his experience as a Microsoft Ambassador and what advice he has for the next wave of students that might be applying for the program now (deadline for applications is September 15th). Here’s what he had to say.

What inspired you to become an MSP?

Two main things inspired me, firstly my brother, who always taught me to strive each and every day to reach each and every goal. Secondly, Microsoft itself inspired me to become an MSP, because of how the company always looks ahead to be the very best, and accepts nothing less.

How would you describe your role as an MSP?

I feel as though my role is one of the most important roles there is. We (as MSP's) are, in some cases, the only representation of Microsoft that some people will ever see. Our outgoing personalities and love for technology and code shows others that even to the very bottom of the totem pole, Microsoft and all of its partners have a passion to be great, and have a solid belief in the company. MSP's exist to ignite the passion for technology (with Microsoft) in others.

What are the benefits of being an MSP?

The hardware and our payment are both great benefits of being an MSP. However, the greatest benefits MSP's receive is the ability to say they have worked with Microsoft and  the networking we are able to do while in this position. Who you know goes a long way in the career hunt and being a partner with Microsoft is one of the greatest possible achievements that one may put on their resume.

What is your favorite thing about being an MSP?

My favorite thing about being an MSP is the opportunities I have been given through this program that has allowed me to meet so many people who share my passion for technology.

What was your most memorable moment as an MSP?

Hands down my most memorable moment as an MSP happened while I was in Seattle as part of the MSP Summit 2014. I stood by the water peering out across the lake at downtown Seattle, and it hit me that I have achieved something I had been working towards for a long time. I was officially one of the best MSP's across the globe. Hitting that achievement/milestone is something I will never forget the rest of my life, and it has inspired me to aim even higher and  continue with my passion for technology and to continue on my path towards my dream job, a full-time Microsoft Employee.

Are there any skills that you have learned or improved on since becoming an MSP?

I could have an endless list of skills that I have learned and improved on, but one of the best skills that I have improved upon is networking. I never truly understood the power of networking until I became an MSP and I had to use all resources to complete my tasks. Now that I have been working towards making my networking skills better, I find myself knowing someone anywhere I go, and having that power is one of the greatest benefits.

What are you looking forward to accomplishing in your MSP role for next year?

This upcoming year my main three goals are:

1. Have a team compete in the finals for Imagine Cup 2015.

2. Gain a Microsoft presence on both Louisiana State University, and Southeastern Louisiana University, as well as start development groups on those campuses.

3. Dramatically increase the number of developers on my campus.

How do you think the MSP program helps you beyond college?

After college, the skills I have learned such as leadership, networking, programming, communication, teamwork, and time management will give me the upper hand no matter where I choose to work. The friendships and connections that I have made can also help me achieve a career and stay on top as one of the best of the best.

The second wave is coming. Will your EMR make the grade?

MSDN Blogs - Tue, 08/26/2014 - 11:19
As I noted in last week’s post, I’ve recently returned from a Healthcare Executive Leadership Summit in Washington, D.C., sponsored by McKesson . Among some of the other invited keynote speakers at the event was Adam Gale, CEO of KLAS . For those of you who may not be familiar with KLAS, it is a research organization whose mission is to improve healthcare technology delivery by honestly, accurately, and impartially measuring vendor performance for their provider partners. Mr. Gale and I had an opportunity...(read more)

Pages

Subscribe to Randy Riness @ SPSCC aggregator
Drupal 7 Appliance - Powered by TurnKey Linux