Sunday, June 15, 2014

Visual Studio 14 with C# 6.0 released

Microsoft has made Visual Studio 14 available to download as Community Technology Preview. It ships with a new compiler for C# and VB written in the languages themselves with the open code available on CodePlex.
Here are my first impressions on new language constructs in C# 6.0 and Visual Studio 14 enhanced editor features.

C# 6.0 language features

Primary constructor

Is defined along with class definition:
  class C(Action subscriber)
  {
    public event Action SomethingHappened = subscriber;
  }
is equivalent to:

  class C
  {
    public C(Action subscriber)
    {
      SomethingHappened = subscriber;
    }
    public event Action SomethingHappened;
  }

What's interesting if I changed the operator from = to += in the event examples above, then the first example (with primary constructor) will not compile. I have no idea why this is disallowed.

Properties with initializers

This is a really great feature useful to have initial value set to an automatic property without having to create backing field.

  class X
  {
    public int P1 { get; set; } = 23;
    private int _p2;
    public int P2
    {
      get { return _p2; }
      set { _p2 = value; }
    } = 24;

    public void Dump()
    {
      WriteLine(P1);          //Shows 23
      WriteLine(P2);         //Shows 0
    }
  }

Interestingly, as shown above you can assign initial value even to a property with accessors implemented but there's no way you could use that value. I find this weird and a bit inconsistent with events. Because you can initialize event (which I understand as a kind of property) with an initial value, you can't do that when the event has accessors defined:

  event Action E = Console.WriteLine; //OK

  event Action E
  { add { } remove { } }
   = Console.WriteLine; //doesn't compile

Declaration expression

Although minor this is the feature I like the most, it makes the parsing and getting from dictionary code much shorter.

  var dict = new Dictionary<string, string>()
  {
    { "Key1", "Value1" }
  };

  if(dict.TryGetValue("Key1", out var value))
  {
    WriteLine(value);
  }

Static imports

Allow to apply using directive to static classes thus use methods and fields from these classes without providing class name.

  using System.Linq.Enumerable;
  using System.Math;

  var numbers = new List<int>() { 1, 2, 3, 4, 5, 6 };
  var result = Round(Average(numbers)) * PI;

  //instead of

  var res = Math.Round(numbers.Average()) * Math.PI;

I imagine static imports can be useful in unit tests to create more readable assertions. I wonder also why these kinds of import is limited to static classes only forbidding static methods from non static classes and structs.

Null-propagation operator

For many this is the most awaited feature.

  string someString = null;
  var result = someString?.Substring(0, 1); //No null reference exception, result set to null

The operator simplifies checking against null and I like the idea of it. But I hope I will not have to use it often since aggressive checking for null everywhere makes the code ugly. I am passionate about ideas like boundaries for null and null object pattern.

There are also some enhancements to exception handling like conditional catch block execution and awaitable calls in catch block.

Visual Studio 14 editor features

Renaming (Ctrl + R + R)

It's really fast and nimble. It works lot faster than ReSharper renaming I think. It could, however, be more sophisticated with renaming of related identifiers e.g. update object names when renaming classes or update backing field when renaming property.

Quick fixes (Ctrl + .) and Refactorings (Alt + .)

They show a preview on a popup.
I love the support you get from quick fixes when you type the code. But for me the preview functionality wouldn't be very useful. I know how the code is going to be changed at the moment I see the light bulb suggestion.

Unlike quick fixes there are no visible suggestions for refactorings and this is a bit uncomfortable. For example in the code below you have to mark the hello + "World" code fragment and then press Alt + . to force IDE to show you the refactoring option. There's no way to show them until the fragment is precisely selected.



Extract methods (Ctrl + R + M)

This is very cool and does not show this annoying popup like Resharper shows.

Other options

Other features include reorder parameters Ctrl + R + O and remove parameters Ctrl + R + V which basically open the same dialog to manage parameters. I would prefer this as a single functionality called Edit parameters and assign it single shortcut.

What's a bit worrying is the delay in code analysis. When you, for instance, change something in the code that makes it uncompilable you have to wait a short but noticeable amount of time for the problematic code fragment to became underlined. Resharper analysis is more immediate I think.

Cannot extract interface (Ctrl + R + I) when there are no public methods in type - if would be nice if it asked to change some to public.

Unfortunately what Visual Studio offers in terms of refactorings is a small subset of what for example Resharper does. But I know that this is a matter of taste. I would be very happy if Visual Studio offered some more fixes and refactorings built in (like go to implementation - on interface method, introduce and initialize field from constructor, add parameter to methods), which I hope would be faster than the ones from external plugins.

Summary


On the whole I like the new features introduced. There aren't very big but I know the most significant effort was spend on the new compiler. The team encourages to submit any problems or suggestions on the Roslyn page on Codeplex. I was very excited to use it and see how new features work and I also submitted a few bugs to the compiler and IDE.

Wednesday, April 23, 2014

Unit testing calls to base class

There is no reasonable way to test whether a method from base class was invoked in derived class. You need to redesign your code to get rid of inheritance so test it thoroughly.

Consider following code where we have a RequestError class responsible for processing that is common to all types of errors. Specialized classes, derive from RequestError and perform additional handling that is specific to the error they represent e.g. show message on dispatcher's console when unauthorized request is made, and use parent handling as well.

public class RequestError
{
  public virtual void Handle(Details requestDetails)
  {
    /*
      Perform logic common to all errors, e.g. logging
      * */
  }
}

public class UnauthorizedRequestError : RequestError
{
  public override void Handle(Details requestDetails)
  {
    ShowOnDispatcherConsole("Unathorized attempt from IP: " + requestDetails.IPAddress);
    base.Handle(requestDetails);
  }

  private void ShowOnDispatcherConsole(string message)
  {
    /*
      ...
    * */
  }
}


To refactor this, I identified all delegations to base class and then removed inheritance and injected dependency object through the constructor. I also extracted interface from this class so it's easier for mocking purposes. The UnauthorizedRequestError now is a kind of decorator around RequestError. The code and test now look like this:

public interface IRequestError
{
  void Handle(Details requestDetails);
}

public class RequestError : IRequestError
{
  public void Handle(Details requestDetails)
  {
    /*
      Perform logic common to all errors, e.g. logging
      * */
  }
}

public class UnauthorizedRequestError : IRequestError
{
  private readonly IRequestError _generalError;

  public UnauthorizedRequestError(IRequestError generalError)
  {
    _generalError = generalError;
  }

  public void Handle(Details requestDetails)
  {
    ShowOnDispatcherConsole("Unathorized attempt from IP: " + requestDetails.IPAddress);
    _generalError.Handle(requestDetails);
  }

  private void ShowOnDispatcherConsole(string message)
  {
    /*
      ...
    * */
  }
}


[Test]
public void ShouldDelegateErrorHandlingToWrappedError()
{
  //GIVEN
  IRequestError generalError = Substitute.For<IRequestError>();
  var unauthorizedError = new UnauthorizedRequestError(generalError);
  var details = new Details();

  //WHEN
  unauthorizedError.Handle(details);

  //THEN
  generalError.Received(1).Handle(details);
}

Saturday, April 12, 2014

Verify event was raised with NSubstitute

I used to unit-test events by subscribing to them with my custom handler which job was to set a flag when the event was called and remember its parameters (if existed). At the end I used assertions to verify if the event was raised and if so whether the parameters were correct.

The behavior I'm going to test is that OfficeDevice should raise Alarm when someone wants to print any document when there is no ink in the device. This is how my tests looked like.

[Test]
public void ShouldAnnounceWhenPrintingWithNoInk()
{
  //GIVEN
  var device = new OfficeDevice(ink: 0);
  InkLevel? level = null;
  device.InkAlarm += (levelParameter) => { level = levelParameter; };

  //WHEN
  device.Print(Any<IDocument>());

  //THEN
  Assert.AreEqual(InkLevel.None, level);
}

This is actually similar to what NSubstitute documentation encourages to do. There's nothing wrong with this. However, a colleague showed me another way of testing events with the spy and verify tactics.

[Test]
public void ShouldAnnounceWhenPrintingWithNoInk()
{
  //GIVEN
  var device = new OfficeDevice(ink: 0);
  var subscriber = Substitute.For<IDummySubscriber>();
  device.InkAlarm += subscriber.React;

  //WHEN
  device.Print(Any<IDocument>());

  //THEN
  subscriber.Received(1).React(InkLevel.None);
}

IDummySubscriber is just a dummy interface for mocking purpose.

public interface IDummySubscriber
{
  void React(InkLevel level);
}


I like the second approach because it's much neater. You can to get rid of flags and lambdas and replace them with mock verification.

Thursday, March 20, 2014

Dealing with minimize of the application from Task Manager

There are some options to minimize a Windows application (in Windows 7) besides using of window control bar:
  • Show desktop button at the end of the notification area on the taskbar,
  • Windows logo button + D combination,
  • Option Show the desktop from the context menu after right click on taskbar

Did you know that Task Manager is also able to minimize Windows application? It does it in a very forceful way. The scenario that is particularly interesting is when an application is showing a modal dialog. Normally it would be impossible to minimize such an application until the modal window is closed but that's not a problem for Task Manager.

When application that displays a modal dialog is minimized form Task Manager, the modal dialog is automatically closed and DialogResult.Cancel is returned from the ShowDialog method.
The dialog is of course not shown again on the restoration.

This is, by contrast, very different from the default behavior of the first three options where the modal window is reopened along with main application window. This is also not applicable for MessageBox which is always reopened.

Is your program prepared for that? I've seen applications that do heavy processing under the cover of modal dialog which is not expected to disappear until it finished its work.
This would be an example of worker modal window that is used sometimes:

 public partial class ModalWindow : Form
  {
    private readonly BackgroundWorker _bw = new BackgroundWorker();

    public ModalWindow()
    {
      InitializeComponent();
    }

    public void StartWorking()
    {
      _bw.DoWork += PerformLengthyAction;
      _bw.RunWorkerCompleted += (o, args) =>
      {
        DialogResult = DialogResult.OK;
        Close();
      };
      _bw.RunWorkerAsync();
    }

    private void PerformLengthyAction(object sender, DoWorkEventArgs doWorkEventArgs)
    {
      Thread.Sleep(15000);
    }
  }

Or, in .NET 4.5 it may be following.

  public partial class ModalWindow : Form
  {
    public ModalWindow()
    {
      InitializeComponent();
    }

    public async void StartWorking()
    {
      var progress = new Progress<string>(text => textBoxLog.AppendText(text));
      await Task.Run(() => PerformLengthyAction(progress));
       DialogResult = DialogResult.OK;
       Close();
    }

    private void PerformLengthyAction(IProgress<string> progress)
    {
      progress.Report("Processing database entries... ");
      Thread.Sleep(5000);
      progress.Report("Done\n");
      progress.Report("Updating IP Cache... ");
      Thread.Sleep(5000);
      progress.Report("Done\n");
      progress.Report("Publishing configuration... ");
      Thread.Sleep(5000);
      progress.Report("Done\n");
    }
  }

It is invoked from main window like this:

  public partial class MainWindow : Form
  {
    private ModalWindow _processingDialog;
    public MainWindow()
    {
      InitializeComponent();
    }

    private void buttonForModalDialog_Click(object sender, EventArgs e)
    {
      _processingDialog = new ModalWindow {DialogResult = DialogResult.None};
      _processingDialog.StartWorking();
      _processingDialog.ShowDialog();
    }
  }

The solutions above is prone to minimization forced by Task Manager.
A quick fix would be to try to reopen the modal dialog on application restore:

  public partial class MainWindow : Form
  {
    ...
    private void MainWindow_Resize(object sender, EventArgs e)
    {
      TryToReopenProcessingDialog();
    }

    private void TryToReopenProcessingDialog()
    {
      if (_processingDialog.DialogResult == DialogResult.Cancel
          && WindowState != FormWindowState.Minimized)
        _processingDialog.ShowDialog();
    }
  }

Friday, November 29, 2013

SQL Server database encryption with CLR user defined types

There aren't many options available when you want to encrypt sensitive data in your database. Enterprise edition of SQL Server has the Transparent Data Encryption feature which is great but this version of SQL Server costs a lot.

The purpose for encryption in a database is to prevent plain data from being written to disc. This is because when database files or backups are accessed by unauthorized people, they would not be able to read the data. The best solution would be a mechanism that automatically performs encryption/decryption on demand and is transparent for the rest of the system.

In this blog post I will show how to encrypt data in a columns by using .NET types that can be imported to SQL Server. Visual Studio 2012 has a project of type SQL Server Database Project. For SQL Server 2008R2, you need to have Target Framework set to 3.5 and Target Platform set to SQL Server 2008 in the project options. Then add new SQL CLR C# User Defined Type like the one below.

using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;


[SqlUserDefinedType(Format.UserDefined,
    IsByteOrdered = true, MaxByteSize = 500)]
[CLSCompliant(false)]
public struct EncryptedString : INullable, IBinarySerialize
{
  private bool is_Null;
  private string _value;

  public bool IsNull
  {
    get
    {
      return (is_Null);
    }
  }

  public static EncryptedString Null
  {
    get
    {
      EncryptedString es = new EncryptedString();
      es.is_Null = true;
      return es;
    }
  }

  public override string ToString()
  {
    if (this.IsNull)
      return "NULL";
    else
    {
      return _value;
    }
  }

  [SqlMethod(OnNullCall = false)]
  public static EncryptedString Parse(SqlString s)
  {
    if (s.IsNull)
      return Null;

    EncryptedString encryptedString = new EncryptedString();
    encryptedString._value = s.Value;

    return encryptedString;
  }

  /*
   * The methods below handle encryption/decryption (here a dummy string reversing)
   * */
  public void Read(System.IO.BinaryReader r)
  {
    var decrypted = Reverse(r.ReadString());
    _value = decrypted;
  }

  public void Write(System.IO.BinaryWriter w)
  {
    var encrypted = Reverse(_value);
    w.Write(encrypted);
  }

  private static string Reverse(string s)
  {
    char[] charArray = s.ToCharArray();
    Array.Reverse(charArray);
    return new string(charArray);
  }
}


I had to use UserDefined serialization format, because the Native (automatic) serialization can handle only some fixed-size primitive types and not strings. This puts the responsibility to handle the binary format on developer, so you need to write code to implement Read and Write methods for the UDT by implementing the IBinarySerialize interface. (more information here)

Having control over how data is written and read gives the opportunity to enrypt it during writing and decrypt when reading. This is the essential point of this approach – no data is being written to disk without prior encryption and everything happens automatically when you insert, select and update the data.

Once the assembly is compiled this is how you load and use it on server.

--REGISTER ASSEMBLY
CREATE ASSEMBLY ClrEncryption
FROM 'C:\ClrTypes\bin\Debug\ClrEncryption.dll' 
WITH PERMISSION_SET = SAFE;

--REGISTER TYPE
CREATE TYPE dbo.EncryptedString 
EXTERNAL NAME ClrEncryption.[EncryptedString];

--CREATE COLUMN OF THAT TYPE
CREATE TABLE dbo.SecretAgents
(ID INT IDENTITY(1,1) PRIMARY KEY, NickName NVARCHAR(50), RealName EncryptedString)

--ENABLE .NET CODE EXECUTION
EXEC sp_configure 'clr enabled', 1
GO
RECONFIGURE
GO

--INSERT VALUES
INSERT INTO dbo.SecretAgents (NickName, RealName) VALUES ('Jason Bourne', 'David Webb')

--SELECTING RAW (SERIALIZED ENCRYTPED) DATA
SELECT NickName, RealName FROM dbo.SecretAgents

--SELECTING DECRYPTED DATA
SELECT NickName, CAST(RealName AS VARCHAR) AS DecryptedRealName FROM dbo.SecretAgents
--OR
SELECT NickName, RealName.ToString() AS DecryptedRealName FROM dbo.SecretAgents


In this example encryption was as simple as reversing the string. In a real world you should use appropriate encryption algorithm like AES, with the keys stored in a secure environment. To debug CLR types you need to attach to SQL Server process.

Wednesday, October 2, 2013

WPF datagrid with filtering (MVVM)

Hi. In this post I would like to present a WPF Datagrid with the filtering capability implemented with pure MVVM approach.

From the user interface perspective, the filtering control is placed inside of the header of the column being filtered (in this case the Name column). The filter is collapsed by default, user needs to expand the expander in the column header to apply filtering. When filter is applied to the grid, the textbox with filter term is highlighted in red.



From the back-end perspective, the filtering is performed directly on the collection bound to the Datagrid. A collection that supports filtering natively is CollectionViewSource, in this case this collection is wrapped around the ObservableCollection. When filter is active it also applies to newly added elements.

Composition code

#region Composition Root
var products = new ObservableCollection<Product>(ProductsStaticSource());
var productsView = new CollectionViewSource { Source = products }.View;
var filteringVm = new FilteringSubViewModel();
DataContext = new ProductsViewModel(productsView, filteringVm, 
  new ProductNameContainsFilter(filteringVm));
#endregion


ProductsView.xaml

<Window x:Class="ExpandableHeader.ProductsView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:ExpandableHeader="clr-namespace:ExpandableHeader"
        Title="Products" Height="350" Width="625">
  <Grid>
    <Grid.Resources>
      <ExpandableHeader:ActivityToBrushConverter x:Key="activityToBrushConverter"/>
    </Grid.Resources>
    <DataGrid AutoGenerateColumns="False" ItemsSource="{Binding Products}">
      <DataGrid.Columns>
        <DataGridTextColumn Header="Id" Binding="{Binding Path=Id}" >
          <DataGridTextColumn.HeaderStyle>
            <Style TargetType="DataGridColumnHeader">
              <Setter Property="VerticalContentAlignment" Value="Top"/>
            </Style>
          </DataGridTextColumn.HeaderStyle>
        </DataGridTextColumn>
        <DataGridTemplateColumn Header="Name" CanUserSort="True" 
        SortMemberPath="Name" MinWidth="110" >
          <DataGridTemplateColumn.CellTemplate>
            <DataTemplate>
              <TextBlock Text="{Binding Name}" />
            </DataTemplate>
          </DataGridTemplateColumn.CellTemplate>
          <!--NAME COLUMN-->
          <DataGridTemplateColumn.HeaderTemplate>
            <DataTemplate>
              <Grid IsHitTestVisible="True">
                <Grid.ColumnDefinitions>
                  <ColumnDefinition/>
                  <ColumnDefinition/>
                </Grid.ColumnDefinitions>
                <TextBlock Grid.Column="0" Text="{TemplateBinding Content}"/>
                <!--FILTER EXPANDER-->
                <Expander Grid.Column="1" IsHitTestVisible="True" 
                VerticalAlignment="Top" Margin="60 -3 0 0" ToolTip="Filter">
                  <Border IsHitTestVisible="True" BorderThickness="1" 
                  Margin="-90 0 0 0" >
                    <StackPanel Margin="0 4 0 0">
                      <!--FILTER TEXTBOX-->
                      <TextBox 
                        Text="{Binding DataContext.FilteringVm.FilterTerm, 
                        RelativeSource={RelativeSource AncestorType=Window}}" 
                        Background="{Binding DataContext.FilteringVm.FilterActive, 
                        RelativeSource={RelativeSource AncestorType=Window}, 
                        Converter={StaticResource activityToBrushConverter}}" 
                        ToolTip="Enter filter term" Width="100" Height="18" FontSize="9" 
                        BorderThickness="1" />
                      <!--FILTER BUTTONS-->
                      <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                        <TextBlock Margin="2">
                        <Hyperlink Command="{Binding DataContext.FilterApply, 
                          RelativeSource={RelativeSource AncestorType=Window}}">
                          Apply
                        </Hyperlink>
                        </TextBlock>
                        <TextBlock Margin="2">
                        <Hyperlink Command="{Binding DataContext.FilterRemove, 
                          RelativeSource={RelativeSource AncestorType=Window}}">
                          Clear
                        </Hyperlink>
                        </TextBlock>
                      </StackPanel>
                    </StackPanel>
                  </Border>
                </Expander>
              </Grid>
            </DataTemplate>
          </DataGridTemplateColumn.HeaderTemplate>

        </DataGridTemplateColumn>
        <DataGridTextColumn Header="Category" Binding="{Binding Path=Category}" />
        <DataGridTextColumn Header="European Article Number (EAN)" 
                    Binding="{Binding Path=EuropeanArticleNumber}" />
        <DataGridTextColumn Header="Description" Binding="{Binding Path=Description}" />
      </DataGrid.Columns>
    </DataGrid>
  </Grid>
</Window>


ProductsViewModel.cs - main view model to handle high level logic, UI commands and bindings.

using System;
using System.ComponentModel;
using System.Windows.Input;

namespace ExpandableHeader
{
  public class ProductsViewModel
  {
    private readonly IFilter _filter;
    public ICommand FilterApply { get; private set; }
    public ICommand FilterRemove { get; private set; }

    public IFilteringSubViewModel FilteringVm
    {
      get;
      private set;
    }

    public ICollectionView Products
    {
      get;
      private set;
    }

    public ProductsViewModel(ICollectionView products,
      IFilteringSubViewModel filteringSubViewModel, IFilter filter)
    {
      Products = products;
      FilteringVm = filteringSubViewModel;
      _filter = filter;
      FilterApply = new DelegateCommand(OnFilterApply);
      FilterRemove = new DelegateCommand(OnFilterRemove);
    }

    public void OnFilterApply()
    {
      FilteringVm.Apply();
      Products.Filter = _filter.Apply;
    }

    public void OnFilterRemove()
    {
      FilteringVm.Clear();
      Products.Filter = null;
    }
  }
}


FilteringSubViewModel.cs - a specific view model to handle filter state. It is a part of the main application view model presented above.

using System.ComponentModel;

namespace ExpandableHeader
{
  public interface IFilterOption
  {
    string FilterTerm { get; }
  }

  public interface IFilteringSubViewModel
  {
    string FilterTerm { get; }
    bool FilterActive { get; }
    void Apply();
    void Clear();
  }

  public class FilteringSubViewModel : INotifyPropertyChanged, 
                IFilterOption, IFilteringSubViewModel
  {
    public event PropertyChangedEventHandler PropertyChanged;

    public FilteringSubViewModel()
    {
      _filterTerm = string.Empty;
    }

    private bool _filterActive;
    private string _filterTerm;

    public string FilterTerm
    {
      get { return _filterTerm; }
      set
      {
        _filterTerm = value;
        NotifyPropertyChanged("FilterTerm");
      }
    }

    public bool FilterActive
    {
      get { return _filterActive; }
      set
      {
        _filterActive = value;
        NotifyPropertyChanged("FilterActive");
      }
    }

    public void Apply()
    {
      FilterActive = true;
    }

    public void Clear()
    {
      FilterTerm = string.Empty;
      FilterActive = false;
    }

    private void NotifyPropertyChanged(string propertyName)
    {
      var handler = PropertyChanged;
      if (handler != null)
      {
        handler(this, new PropertyChangedEventArgs(propertyName));
      }
    }
  }
}


ProductNameContainsFilter.cs - class for filtering of products by their name.

using System;

namespace ExpandableHeader
{
  public interface IFilter
  {
    bool Apply(object parameter);
  }

  public class ProductNameContainsFilter : IFilter
  {
    private readonly IFilterOption _filterOption;

    public ProductNameContainsFilter(IFilterOption filterOption)
    {
      _filterOption = filterOption;
    }

    public bool Apply(object parameter)
    {
      return ((Product)parameter).Name.IndexOf
               (_filterOption.FilterTerm, 
                StringComparison.InvariantCultureIgnoreCase)
               >= 0;
    }
  }
}


Download VS 2010 code

Monday, August 26, 2013

What is TemplateBinding in WPF – short example.

TemplateBinding has to do with the ControlTemplate, in brief it is a way to inject property into the template from the template user. You've probably heard about the lookless nature of WPF controls which means that unlike behavior (which is fixed), the appearance of a control can be replaced entirely by supplying a new ControlTemplate.

Consider the following template for a ToggleButton. This is simply a polygon with a stroke and an orange fill.
<Window x:Class="TemplateBindingTest.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.Resources>
  <Style x:Key="PolygonToggleButtonStyle" TargetType="ToggleButton">
    <Style.Setters>
      <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ToggleButton">
            <Polygon Name="CenterPolygon" Points="90,10 50, 50, 10,10" 
            Fill="Orange" Stroke="Gray" StrokeThickness="0"/>
            <ControlTemplate.Triggers>
              <Trigger Property="IsChecked" Value="True">
                <Setter TargetName="CenterPolygon" Property="StrokeThickness" Value="3"/>
              </Trigger>
            </ControlTemplate.Triggers>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style.Setters>
  </Style>
</Grid.Resources>

<StackPanel Width="100">
  <ToggleButton Background="Pink" Style="{StaticResource PolygonToggleButtonStyle}"/>
</StackPanel>
</Grid>
</Window>

See that in spite of setting the Background property to Pink, the button is still orange since this is the value hardcoded in template.


Because we provided our own ControlTemplate we must explicitly say how the template should use parameters provided by the control's user. This is a situation when TemplateBinding becomes handy. We will instruct the Fill property to capture the value of Background property in the following way.

<Polygon Name="CenterPolygon" Points="90,10 50, 50, 10,10" 
Fill="{TemplateBinding Background}" Stroke="Gray" StrokeThickness="0"/>