Before you go on, let me summarize this long post for you: while it is possible to clone a control template in order to change just some things in it, it is a difficult and error prone process. The code at the end of the post is a proof of concept thing, which works for simple scenarios, but needs additional work for complicated controls.

I was exploring the option of not overwriting the ControlTemplate of a WPF Control when I try adding stuff to it. Instead, I tried to get the ControlTemplate and manipulate it before putting it back. It is not as easy as it seems. Even more, people stack over each other to advise everybody not to do it. I am not saying it is an easy option, so my advice is to try other alternatives, if you have them, but the idea is: it can be done!

Let's take it step by step. In order to get the control template we should get it as soon as it is available, but perhaps before applying it. One could override OnApplyTemplate and do it there or, as it is my case (trying to do it via attached properties and lacking an ApplyingTemplate event), do it once when the control is initializing. The control template is easily obtained via the Template property. If you try to change anything in it, though, you will get an exception, because the template is sealed. So the only option is to clone it, change stuff in it, then set the control template to that clone.

The template is of type ControlTemplate, but it doesn't seem to contain much. It has Resources and Triggers properties, also a VisualTree property and a LoadContent method. There is also a Template property in the ControlTemplate class... try to set it and a null exception will be thrown, so forget it. The first two are easy to use, just iterate through the collections. VisualTree is of the weird and undocumented type FrameworkElementFactory, while LoadContent is a method that returns a DependencyObject.

Well, the idea is that LoadContent will return the content of the template which you should use to set the VisualTree property, but the process of getting a DependencyObject and getting a FrameworkElementFactory tree is not simple.

First things first: get a new ControlTemplate. Its contructor gets a Type parameter which we take from the TargetType property of the original template. We then add any resources from the original template to the resources of the new one. Next step is to take the content, using LoadContent, which will get us the first child of the element tree. In order to traverse it we will use the VisualTreeHelper static class which exposes the GetChildrenCount and GetChild methods.

The next step is to create a FrameworkElementFactory. It has a constructor which receives a Type and another which gets a Type and a name string. We will use the first, since the Name can be set afterwards. The type we get from the type of the DependencyObject returned by LoadContent. The VisualTree of the new control template will have to be this new factory object, but it also needs all the properties of the original object as well as all its children.

In order to get the dependency and attached properties of each element we will use the MarkupWriter.GetMarkupObjectFor method, which returns a MarkupObject. Each of its Properties will have a DependencyProperty property which will give us the properties. However, the value of the property is not so easy to get. If we use GetValue, any binding or markup extensions will be evaluated and probably give wrong results (since the control has not been initialized yet). Using ReadLocalValue brings us pretty close, only that for certain objects like Binding we don't get a BindingBase object, but a BindingExpressionBase. We need to cast the value we get to BindingExpressionBase and TemplateBindingExpression and get to the underlying binding object.

Now that we've got the properties and the correct values, we use the factory SetValue method to set it. A special case is Name which must be set directly to the Name property. We use AppendChild to add a factory to a parent factory.

The last step is to get the Triggers from the original template and copy it in the new one. Now Seal it and you have yourself a clone. Not sure how one would manipulate the template to get a usable and maintainable template manipulation, but this is how you start.

I know you are suckers for code, so here it is:

Update: Actually the collapsed code below doesn't work except for the simplest of templates. There are several reasons for it and I will explore them below.
Click to expand


The first problem I found was dependency properties registered as read only that could only be set from XAML, like VisualStateManager.VisualStateGroups. When trying to use the FrameworkElementFactory SetValue method it would throw an error. Funny enough, the only reason that happened is because said method is checking if the property is read only and throws an exception. I had to use reflection to circumvent this, and it worked, albeit really ugly.

The second problem was more basic. Not every property is a dependency property. Such a simple property is Grid.ColumnDefinitions! Not only it is not a dependency property, but it is also read only. So I had to find another mechanism to fix this. At this point you probably realise this method is not a good one to employ, but if you are really desperate (or stubborn, like me) there is a way. The solution I found is to save all the properties that I need to set into a list and then set them in a RoutedEventHandler invoked from the Loaded event!

And if this is not enough, simply setting the value from the template in the control doesn't always work. In the generated template control the ColumnDefinition objects are already in the ColumnDefinitionCollection of the control. Adding them to a control that the factory generates results in an error. What I did here is a simple value=XamlReader.Parse(XamlWriter.Save(value)).

In other cases, like the Border.Child property, it must be completely ignored! So a list of properties to be ignored is needed.

Conclusion: Some improvements have been done in the code, but it's a little larger than before. The complicated way in which this works makes it cumbersome to be used, and I would not recommend it, but it works and it has extension points where errors with properties can be handled. Here is the new code:
#region Using directives

using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;

#endregion

namespace BestPractices
{
/// <summary>
/// Base class for ControlTemplate transforming classes
/// </summary>
public abstract class BaseTemplateTransformer : BaseControlTransformer
{
#region Public Methods

/// <summary>
/// Clones the ControlTemplate of a control and allows for its manipulation
/// </summary>
/// <param name="control"></param>
public override void Transform(Control control)
{
ControlTemplate template = control.Template;
if (template == null)
{
return;
}
// create new template
ControlTemplate newTemplate = new ControlTemplate(template.TargetType);
// copy the resources
foreach (object key in template.Resources.Keys)
{
newTemplate.Resources.Add(key, template.Resources[key]);
}
//get the VisualTree factory from the original template content
DependencyObject content = template.LoadContent();
newTemplate.VisualTree = OnGetElementFactory(content);
// copy the triggers
foreach (TriggerBase trigger in template.Triggers)
{
newTemplate.Triggers.Add(trigger);
}
// allow for template manipulation
OnBeforeSeal(newTemplate);
// seal the template and set it back
newTemplate.Seal();
control.Template = newTemplate;
}

/// <summary>
/// Creates a custom ControlTransformFactory for the content object.
/// Override in order to replace elements in the initial template.
/// </summary>
/// <param name="content"></param>
/// <returns></returns>
public virtual ControlTransformFactory OnGetElementFactory(DependencyObject content)
{
if (content == null)
{
return null;
}
// use the object type
ControlTransformFactory factory = new ControlTransformFactory(content, this);
return factory;
}

/// <summary>
/// Returns a safe value for setting on the control
/// </summary>
/// <param name="item">The value from the template</param>
/// <returns></returns>
public virtual object GetSafeValue(object item)
{
return getSafeValue((dynamic) item);
}

/// <summary>
/// Returns true if a property needs to be saved and set when the control loads.
/// Defaults to false, except for ColumnDefinitions and RowDefinitions
/// </summary>
/// <param name="propertyDescriptor"></param>
/// <returns></returns>
public virtual bool MustSetProperty(PropertyDescriptor propertyDescriptor)
{
return sMustSetProperties.Contains(propertyDescriptor.Name);
}

#endregion

#region Protected Methods

/// <summary>
/// Allows for the manipulation of a control template
/// </summary>
/// <param name="newTemplate"></param>
protected virtual void OnBeforeSeal(ControlTemplate newTemplate)
{
}

#endregion

#region Statics

private static readonly List<string> sMustSetProperties = new List<string>
{
"ColumnDefinitions",
"RowDefinitions"
};

/// <summary>
/// Transforms a DependencyObject tree into a FrameworkElementFactory tree
/// </summary>
/// <param name="content"></param>
/// <returns></returns>
public static ControlTransformFactory CreateElementFactory(DependencyObject content)
{
if (content == null)
{
return null;
}
// use the object type
ControlTransformFactory factory = new ControlTransformFactory(content);
return factory;
}

/// <summary>
/// default return the same value
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
private static object getSafeValue(object value)
{
return value;
}

/// <summary>
/// try to clone ColumnDefinition objects
/// </summary>
/// <param name="columnDefinition"></param>
/// <returns></returns>
private static object getSafeValue(ColumnDefinition columnDefinition)
{
return clone(columnDefinition);
}

/// <summary>
/// try to clone RowDefinition objects
/// </summary>
/// <param name="rowDefinition"></param>
/// <returns></returns>
private static object getSafeValue(RowDefinition rowDefinition)
{
return clone(rowDefinition);
}

/// <summary>
/// Clones an item via Xaml write/parse
/// </summary>
/// <param name="element"></param>
/// <returns></returns>
private static object clone(object element)
{
string str = XamlWriter.Save(element);
return XamlReader.Parse(str);
}

#endregion
}
}

#region Using directives

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using System.Windows;
using System.Windows.Markup.Primitives;
using System.Windows.Media;

#endregion

namespace BestPractices
{
/// <summary>
/// FrameworkElementFactory used in control template transformers
/// </summary>
public class ControlTransformFactory : FrameworkElementFactory
{
#region Nested

internal class NoTemplateTransformer : BaseTemplateTransformer
{
}

#endregion

#region Instance fields

private readonly BaseTemplateTransformer mTemplateTransformer;

private RoutedEventHandler mLoadHandler;
private List<MarkupProperty> mSimpleProperties;

#endregion

#region Properties

/// <summary>
/// List of non dependency properties that will be set when the control loads
/// </summary>
protected List<MarkupProperty> SimpleProperties
{
get
{
if (mSimpleProperties == null)
{
mSimpleProperties = new List<MarkupProperty>();
}
return mSimpleProperties;
}
}

#endregion

#region Constructors

public ControlTransformFactory(DependencyObject content,
BaseTemplateTransformer templateTransformer = null)
: base(content.GetType())
{
mTemplateTransformer = templateTransformer ?? new NoTemplateTransformer();
// set its name
string name = content.GetValue(FrameworkElement.NameProperty) as string;
if (!string.IsNullOrWhiteSpace(name))
{
Name = name;
}
// copy the properties
foreach (MarkupProperty propertyItem in getProperties(content))
{
SetProperty(propertyItem);
}
// do it recursively
int count = VisualTreeHelper.GetChildrenCount(content);
for (int i = 0; i < count; i++)
{
DependencyObject child = VisualTreeHelper.GetChild(content, i);
AppendChild(mTemplateTransformer.OnGetElementFactory(child));
}
}

#endregion

#region Public Methods

/// <summary>
/// SetValue that uses reflection to force DependencyProperties that were registered as read only
/// </summary>
/// <param name="dependencyProperty"></param>
/// <param name="value"></param>
/// <param name="forceSetReadOnly"></param>
public void SetValue(DependencyProperty dependencyProperty, object value,
bool forceSetReadOnly = false)
{
if (!forceSetReadOnly)
{
base.SetValue(dependencyProperty, value);
}
else
{
forceSetValue(dependencyProperty, value);
}
}

/// <summary>
/// Sets a value from a MarkupProperty object.
/// Dependency properties will be set via SetValue and the others via a Loaded handler on the object
/// </summary>
/// <param name="propertyItem"></param>
public void SetProperty(MarkupProperty propertyItem)
{
DependencyProperty property = propertyItem.DependencyProperty;
if (property == null)
{
setSimpleProperty(propertyItem);
}
else
{
object value = propertyItem.Value;
if (value == DependencyProperty.UnsetValue)
{
return;
}
SetValue(property, value, property.ReadOnly);
}
}

#endregion

#region Private Methods

/// <summary>
/// Force set value in the factory, even if the property is ReadOnly
/// </summary>
/// <param name="dp"></param>
/// <param name="value"></param>
private void forceSetValue(DependencyProperty dp, object value)
{
object resourceKey = getResourceKey(value);
if (resourceKey == null)
{
updatePropertyValueList(dp, value is TemplateBindingExtension
? "TemplateBinding"
: "Set", value);
}
else
{
updatePropertyValueList(dp, "Resource", value);
}
}

/// <summary>
/// Invoke the private UpdatePropertyValueList on the factory
/// </summary>
/// <param name="dp"></param>
/// <param name="propertyValueTypeName"></param>
/// <param name="value"></param>
private void updatePropertyValueList(DependencyProperty dp,
string propertyValueTypeName, object value)
{
object propertyValueType = Enum.Parse(sPropertyValueTypeType, propertyValueTypeName);
sUpdatePropertyValueListProperty.Invoke(this, new[] {dp, propertyValueType, value});
}

/// <summary>
/// Set a property to have its value set at load time
/// </summary>
/// <param name="markupProperty"></param>
private void setSimpleProperty(MarkupProperty markupProperty)
{
if (markupProperty.PropertyDescriptor == null)
{
return;
}
if (!mTemplateTransformer.MustSetProperty(markupProperty.PropertyDescriptor))
{
return;
}
SimpleProperties.Add(markupProperty);
if (mLoadHandler == null)
{
mLoadHandler = new RoutedEventHandler(simplePropertyHandler);
AddHandler(FrameworkElement.LoadedEvent, mLoadHandler);
}
}

/// <summary>
/// Handler on the Loaded event of the control
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
private void simplePropertyHandler(object sender, RoutedEventArgs args)
{
foreach (MarkupProperty propertyItem in SimpleProperties)
{
PropertyDescriptor propertyDescriptor = propertyItem.PropertyDescriptor;
if (propertyDescriptor == null || propertyItem.Value == null)
{
continue;
}
if (propertyDescriptor.IsReadOnly)
{
IList list = propertyItem.Value as IList;
if (list != null)
{
IList destinationList = propertyDescriptor.GetValue(sender) as IList;
if (destinationList != null)
{
foreach (object item in list)
{
destinationList.Add(mTemplateTransformer.GetSafeValue(item));
}
}
else
{
//shouldn't happend
}
}
else
{
// what now?
}
}
else
{
propertyDescriptor.SetValue(sender, mTemplateTransformer.GetSafeValue(propertyItem.Value));
}
}
FrameworkElement element = (FrameworkElement) sender;
element.RemoveHandler(FrameworkElement.LoadedEvent, mLoadHandler);
}

#endregion

#region Statics

static ControlTransformFactory()
{
// Get the types and methods that will be used in Reflection scenarios
sUpdatePropertyValueListProperty =
typeof (FrameworkElementFactory).GetMethod("UpdatePropertyValueList",
BindingFlags.NonPublic | BindingFlags.Instance);
sPropertyValueTypeType =
typeof (FrameworkElementFactory).Assembly.GetType("System.Windows.PropertyValueType");
}

private static readonly MethodInfo sUpdatePropertyValueListProperty;
private static readonly Type sPropertyValueTypeType;

/// <summary>
/// get the properties set on a DependencyObject
/// </summary>
/// <param name="content"></param>
/// <returns></returns>
private static IEnumerable<MarkupProperty> getProperties(DependencyObject content)
{
MarkupObject markupObject = MarkupWriter.GetMarkupObjectFor(content);
return markupObject.Properties;
}

/// <summary>
/// Get the ResourceKey property from an object, if it exists
/// </summary>
/// <param name="target"></param>
/// <returns></returns>
private static object getResourceKey(object target)
{
if (target == null)
{
return null;
}
Type type = target.GetType();
PropertyInfo property = type.GetProperty("ResourceKey");
if (property == null)
{
return null;
}
return property.GetValue(target, new object[] {});
}

#endregion
}
}

and has 3 comments
In order to programmatically load a .crx Chrome extension as an external extension, the ID of the extension is required. The algorithm for computing it is:
  1. make a SHA256 hash of the public key embedded in the .crx file
  2. take the first 128bits (16 bytes) and encode them in base16
  3. use characters a-p instead of the customary 0-9,A-F


For this we need, obviously, the public key. Reading from the CRX Package Format page, we can determine we need a 4 byte (Int32) value of the public key length and the public key itself. The length is found at position 8 in the file, the public key starts at position 16. Here is the code:

private byte[] getPublicKey(FileInfo fi)
{
using (
FileStream stream = File.Open(fi.FullName,
FileMode.Open,
FileAccess.Read,
FileShare.ReadWrite))
{
byte[] arr = new byte[4];
stream.Seek(8, SeekOrigin.Begin);
stream.Read(arr, 0, arr.Length);
var publicKeyLength = BitConverter.ToInt32(arr, 0);
arr = new byte[publicKeyLength];
stream.Seek(16, SeekOrigin.Begin);
stream.Read(arr, 0, arr.Length);
return arr;
}
}


The code to create the id is now simple:

private string getExtensionId(byte[] publicKey)
{
SHA256 sha = SHA256.Create();
publicKey = sha.ComputeHash(publicKey);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 16; i++)
{
byte b = publicKey[i];
char ch = (char)('a' + (b >> 4));
sb.Append(ch);
ch = (char)('a' + (b & 0xF));
sb.Append(ch);
}
return sb.ToString();
}


Just in case you want to get a complete class that handles .crx files, here it is:

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Web.Script.Serialization;
using SevenZip;

namespace ChromeExtensionInstaller
{
internal class CrxPack
{
#region Instance fields

private byte[] mContent;
private SevenZipExtractor mExtractor;
private dynamic mManifest;
private Uri mUri;
private string mPath;

#endregion

#region Properties

public Exception InvalidReason
{
get;
private set;
}

public bool IsValid
{
get;
private set;
}

private dynamic Manifest
{
get
{
if (mManifest == null)
{
FileInfo fi = new FileInfo(mUri.AbsolutePath);
mManifest = getManifest(fi);
}
return mManifest;
}
}

public string Id
{
get
{
return getExtensionID();
}
}

public string Name
{
get
{
return Manifest.name as string;
}
}

public string Version
{
get
{
return Manifest.version as string;
}
}

public string Path
{
get
{
return mPath;
}
}

#endregion

#region Constructors

public CrxPack(string path)
{
mPath = path;
try
{
checkPath(path);
IsValid = true;
}
catch (Exception ex)
{
IsValid = false;
InvalidReason = ex;
}
}

#endregion

#region Private Methods

private void checkPath(string path)
{
mUri = ExtensionHelper.GetUri(path);
if (mUri == null)
{
throw new Exception(string.Format("Parameter is not a valid URI ({0})", mPath));
}
mPath = mUri.AbsolutePath;
if (!mUri.IsFile && !mUri.IsUnc)
{
throw new Exception(string.Format("Only file and local network paths are acceptable ({0})",
mPath));
}
DirectoryInfo di = new DirectoryInfo(mPath);
if (di.Exists)
{
throw new Exception(string.Format(
"Loading extensions from folders is not implemented ({0})", mPath));
}
FileInfo fi = new FileInfo(mPath);
if (!fi.Exists)
{
throw new Exception(string.Format("The file does not exist ({0})", mPath));
}
if (fi.Extension.ToLower() != ".crx")
{
throw new Exception(string.Format("The file extension must be a .crx file ({0})", mPath));
}
try
{
mExtractor = getExtractor(fi);
if (mExtractor.Check())
{
return;
}
}
catch (Exception ex)
{
throw new Exception(
string.Format("The file could not be read as a valid .crx file ({0})", mPath), ex);
}
throw new Exception(string.Format("The file could not be read as a valid .crx file ({0})",
mPath));
}


private SevenZipExtractor getExtractor(FileInfo fi)
{
byte[] arr;
using (
FileStream stream = File.Open(fi.FullName, FileMode.Open, FileAccess.Read,
FileShare.ReadWrite))
{
arr = new byte[fi.Length];
mContent = arr;
stream.Read(arr, 0, arr.Length);
}
// force PkZip signature
arr[0] = 0x50;
arr[1] = 0x4B;
arr[2] = 0x03;
arr[3] = 0x04;
MemoryStream ms = new MemoryStream(arr);
return new SevenZipExtractor(ms);
}

private string getExtensionID()
{
int length = readInt(8);
byte[] bytes = readBytes(16, length);
SHA256 sha = SHA256.Create();
bytes = sha.ComputeHash(bytes);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 16; i++)
{
byte b = bytes[i];
char ch = (char) ('a' + (b >> 4));
sb.Append(ch);
ch = (char) ('a' + (b & 0xF));
sb.Append(ch);
}
return sb.ToString();
}

private int readInt(int index)
{
byte[] bytes = readBytes(index, 4);
return BitConverter.ToInt32(bytes, 0);
}

private byte[] readBytes(int index, int length)
{
byte[] bytes = new byte[length];
Array.Copy(mContent, index, bytes, 0, length);
return bytes;
}

private object getManifest(FileInfo fi)
{
SevenZipExtractor extractor = getExtractor(fi);
string json;
using (MemoryStream ms = new MemoryStream())
{
extractor.ExtractFile("manifest.json", ms);
ms.Seek(0, SeekOrigin.Begin);
StreamReader sr = new StreamReader(ms);
json = sr.ReadToEnd();
}
JavaScriptSerializer serializer = new JavaScriptSerializer();
serializer.RegisterConverters(new[] {new DynamicJsonConverter()});
return serializer.Deserialize(json, typeof (object));
}

#endregion
}
}


You need to reference the SevenZipSharp library and place 7z.dll (from the 7-Zip archiver) in the same folder with the application using this class.

and has 1 comment
I was trying to verify an SHA256 signature (don't ask) and so I had to use the class SHA256CryptoServiceProvider. Alas, the constructor promptly threw an exception telling me the class is not supported on my system. I googled it and found this answer: C# - SHA256CryptoServiceProvider and related possible to use on WinXP?. Whereas the link reports this is a bug in .NET 3.5 I am working with version 4.0 and it is still there.

Apparently, the constructor of SHA256CryptoServiceProvider looks for a certain name in the cryptography providers installed on the machine. It looks for "Microsoft Enhanced RSA and AES Cryptographic Provider" and it gets the XP variant "Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)". The solution is to export the key, remove "(Prototype)" and install the resulting reg file. Then it works. Here is the file, as it resulted on my computer:
Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Defaults\Provider\Microsoft Enhanced RSA and AES Cryptographic Provider]
"Image Path"="rsaenh.dll"
"Type"=dword:00000018
"SigInFile"=dword:00000000

Update: in order to execute a script in any open tab inside Chrome, use the executeScript method of the tabs API.

Chrome browser extensions are so cool, that they protect you from accidentally running and adding script to a page that might interfere with the original code of the page. Unfortunately, they don't give you a parameter or option to actually do that, if it is what you actually want. All you can do, by default, is to access the elements in the page document, but not change direct members of window or even document.

I have found the solution on this page: Writing a Google Chrome extension: How to access the global context of the embedding page through a content script.. There is code and explanations for the code, but basically it is a function that injects another function in the real page context and also returns a result.

I had this control that consisted of a textbox and a squigly red line in case of a required value error. In order to do it, I added the textbox and the line to a Grid, without specifying column or row values, so that the line would come above the textbox. It all worked well until I wanted to make the control align to the left, thus growing with the content entered in it. To my surprise, the control would stretch to the content width when in edit mode and go to 202 pixels outside it. The only things in the template were a textbox and a line inside a grid and a border, so I proceeded on inspecting all of their attributes in search for the culprit. It so happens that the Line was it!

Update: The Microsoft guys responded in a day to my bug report, but they couldn't reproduce it. It seems this behavior can be reproduced only in a Grid column with Width="Auto". Frankly, I was a bit surprised to see that, lacking that grid column, a line with Stretch="Fill" and HorizontalAlignment to "Left" would still expand the container to its maximum size. End update.
The code looked like this:

<Style x:Key="StyleRequiredUnderline" TargetType="{x:Type Line}">
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="Stretch" Value="Fill"/>
<Setter Property="X1" Value="0"/>
<Setter Property="X2" Value="1"/>
<Setter Property="Y1" Value="0"/>
<Setter Property="Y2" Value="0"/>
<Setter Property="MaxWidth" Value="200"/>
</Style>

<Grid>
<TextBlock x:Name="TextBlock" />
<Line Name="RequiredUnderline" Style="{StaticResource StyleRequiredUnderline}"
/>
</Grid>
As you can see, the line is Left aligned, it has no specified Width, the only giveaway is the Stretch property set to Fill. Now, you think that was the problem, but it was not! See that I have a MaxWidth of 200. That was per request.

It appears that if I remove the MaxWidth setting, the line goes DOWN to the normal size of the parent inner width. MaxWidth, not MinWidth, mind you. Ok, so I've tried some other things. Stretch to None makes the line be 1px long. Setting X2 to 200 makes the line take 200px, same as setting Width. HorizontalAlignment to Stretch makes the line go to the center of the space if it is bigger than the 200 MaxWidth.

The solution? I've bound the Width of the line to the ActualWidth of the TextBlock above. Another option would have been to surround the line with a scrollviewer or some other control that would allow the line to be as long as it wanted without showing a scrollbar or stretching to the size of its content. Either solution seems bad.

Is this a bug? I think so. If the Stretch property should have affected the space the line takes, then it should have done so when MaxWidth was set to Infinity, but it did not. Well, hopes it helps someone. Final code piece for the line:

<Grid>
<TextBlock x:Name="TextBlock" />
<Line Name="RequiredUnderline" Style="{StaticResource StyleRequiredUnderline}"
Width="{Binding ActualWidth,ElementName=TextBlock}" />
</Grid>


Update: The fix I've exemplified above doesn't work when the HorizontalAlignment of the grid is Stretch or has a Width and the TextBox doesn't have a Left HorizontalAlignment. I have tried to replace the Line with a ScrollViewer with hidden scrolling on the horizontal and disabled on the vertical and having a MaxWidth of 200, Inside placing the troublesome Line. I've tried all kinds of panels and combinations of HorizontalAlignment, HorizontalContentAlignment, ClipToBounds, etc. All to no avail.

Finally, the solution was to create a simple control that would ignore the dimensions of the child controls, demanding no space. I named it ClipContainer and here is its source:

public class ClipContainer : ContentControl
{
protected override Size MeasureOverride(Size availableSize)
{
base.MeasureOverride(availableSize);
return new Size(0, 0);
}
}

<Grid>
<TextBlock x:Name="TextBlock" />
<local:ClipContainer>
<Line Name="RequiredUnderline" Style="{StaticResource StyleRequiredUnderline}" />
</local:ClipContainer>
</Grid>
I've put the line in this control, MaxWidth and all, and the control stretched to the size of its container and clipped all of its contents.

Also, like any responsible developer , I went to Microsoft Connect to add this issue as a bug. Here is the bug report. Vote it up if it affects you.

Sometimes, when working with a WPF application, Snoop would crash with the most innovative error messages possible. One of these was 'Object' type does not have a matching DependencyObjectType. Well, of course it doesn't, but where does this come from, why only when I use Snoop and how do I fix it?

I won't bore you with the details, enough said I have traced the problem to an AttachedPropertyBrowsableForTypeAttribute I have used on an attached property. I was using a Resharper Live Template (a snippet) to generate the code for the property and I'd accidentally forgot to set a proper type in the attribute and left the default object.

The thing looked like this:

[AttachedPropertyBrowsableForType(typeof (object))]
Replacing object with my control fixed the Snoop crash.

I had this container that I wanted to handle any mouse click events. So I proceeded on creating an attached property that has a property changed callback in which I would take the element and add a mouse handler to it. Pretty standard stuff, only it didn't quite work. It also blocked any events in the children. As I knew this should have happened in Preview events, not in normal events, I was stumped.

The problem: the attached property was defined with FrameworkPropertyMetadataOptions.Inherits which meant its value applied to all the children, meaning the value changes on all children when I set it on the parent. That meant the handler for the mouse click events was attached to the container and each of its descendants.

I was comparing these two MySQL queries. They looked the same, except for some extra joins and groups, but one was lasting for 5 seconds, the other for 2 minutes. I removed all extra stuff from the long lasting query to get to an almost identical query as the first, only to see it run for two minutes again. The only difference was the type of a WHERE clause. Instead of comparing date with "20101012" (string) I would compare it with 20101012 (integer). Apparently, the type conversion alone was invalidating any use of the index on the date column and made the query last forever. Good to know.

The scenario is that an Image that has its Stretch property set to None still has a different size from the original image source. You check the Padding, the Margin, the VerticalAlignment and HorizontalAlignment properties, you play with the RenderOptions and SnapsToDevicePixels and nothing seems to work. You specify the Width and Height manually and the image is clipped. The problem here, believe it or not, is that the DPI setting of the image source is different from the system DPI setting.

The solution is an ugly thing:

<Image
Stretch="Fill"
Width="{Binding RelativeSource={RelativeSource Self}, Path=Source.PixelWidth}"
Height="{Binding RelativeSource={RelativeSource Self}, Path=Source.PixelHeight}"/>
So set the Stretch to Fill so that it doesn't fill!

Here is the discussion where I got the solution from: How do I keep an image from being stretched when Stretch="None" doesn't work?.

The scenario is easy enough to create: make a Brush, use a Binding as the Color property, use your brush in your app, then start the application and change the system theme. An error "This freezable can not be frozen" will be triggered. The solution is to set x:Shared="False" for the brushes with color bindings.

An entire Microsoft Connect page is devoted to this issue, so get all the details there: Changing system theme throws "This freezable can not be frozen" exception

Update February 2016: The Microsoft Connect page has disappeared. Maybe it was because the bug was marked as "closed - by design", or some other Microsoft site revamp idiocy.

I had this control where a button was displaying a ContextMenu. I wanted to keep the ContextMenu open so I can manipulate its content. I had assumed that the StaysOpen property would do that for me; it did not. Also, I tried using a ContextMenuClosing event approach, only to discover that it is one of those rare "ing" events that doesn't have a Cancel property. I've looked in the sources of ContextMenu and Popup to see just what is going on and I have decided that the design was impossible to patch in order to get the behaviour I wanted.

In the end, the only solution I could find was to inherit from ContextMenu into a new class that would coerce the IsOpen property to true when StaysOpen is set to true. That did the trick. Here is the code:

public class StaysOpenContextMenu:ContextMenu
{
static StaysOpenContextMenu()
{
fixContextMenuStaysOpen();
}

private static void fixContextMenuStaysOpen()
{
IsOpenProperty.OverrideMetadata(
typeof(StaysOpenContextMenu),
new FrameworkPropertyMetadata(false, null,coerceIsOpen));
StaysOpenProperty.OverrideMetadata(
typeof(StaysOpenContextMenu),
new FrameworkPropertyMetadata(false, null, coerceStaysOpen));
}

private static object coerceStaysOpen(DependencyObject d, object basevalue)
{
d.CoerceValue(IsOpenProperty);
return basevalue;
}

private static object coerceIsOpen(DependencyObject d, object basevalue)
{
ContextMenu menu = (ContextMenu)d;
if (menu.StaysOpen)
{
return true;
}
return basevalue;
}

}


Hope it helps people out.

Update:

This solution only works for the body of the ContextMenu, the submenus are something else. However, the submenus are defined in the control template of a menu item, so that can be easily remedied by changing it to your needs. One quick and dirty solution would be to add a trigger that sets the IsSubMenuOpen property to true whenever StaysOpenOnClick is set. Or, if you simply want to freeze a menu in place, change the template so that the mouse click or hover will only trigger IsSubMenuOpen when the parent ContextMenu has StaysOpen to false, while the StaysOpen property of the MenuItem Popup is set to the ContextMenu StaysOpen.

Ok, I am working on the blog to make it more accessible. I've replaced the template, I made all changes in the template from javascript and CSS, not by editing it and I've removed many of the things clogging the site. Not the cats and flies, though :) The light (low band) version of the site is not working anymore. If you want just the content, you can open the RSS feed.

I would like to know what you are thinking about the new look and I hope I will find the time to write interesting posts.

I haven't been the most present of hosts, but then again, I haven't seen much interest for the collaboration page, with its open chat and whiteboard. Therefore I replaced the link to it with the Plugoo chat. The blog desperately needs some refactoring, but not likely that it will happend soon.

I was working on this application and so I found it easy to create some controls as UserControl classes. However, I realised that if I wish to centralize the styling of the application or even move some of the controls in their own control library with a Themes folder, I would need to transform them into Control classes.

I found that there are two major problems that must be overcome:

  1. the named controls in a user control can be accessed as fields in the code behind; a theme style does not allow such direct access to the elements in the control template.
  2. the controls that expose an event may not expose an associated command. In a user control a simple code behind handler method can be attached to a child control event, but in a theme a command must be available in order to be bound.



Granted, when the first problem is solved, it is easy to attach events in the code of the control to the child elements, but this presents two very ugly problems: the template of the control will need to contain the child elements in question and the event will not be declared in the theme, so the behaviour would be fixed as well.

I will solve the handling of events as commands by using a solution from Samuel Jack. The article is pretty detailed, but to make the story short, one creates an attached property for each of the handled events by using a helper class:


public static class TextBoxBehaviour
{
public static readonly DependencyProperty TextChangedCommand =
EventBehaviourFactory.CreateCommandExecutionEventBehaviour(
TextBox.TextChangedEvent, "TextChangedCommand", typeof (TextBoxBehaviour));

public static void SetTextChangedCommand(DependencyObject o, ICommand value)
{
o.SetValue(TextChangedCommand, value);
}

public static ICommand GetTextChangedCommand(DependencyObject o)
{
return o.GetValue(TextChangedCommand) as ICommand;
}
}

then by using a very simple syntax on the control that fires the event:


<TextBox ff:TextBoxBehaviour.TextChangedCommand="{Binding TextChanged}"/>



The problem regarding access to the elements in the template is solved by reading the elements by name from the template. In some situations, like when one uses a control as a source for a data control (like using a TreeView as the first item in a ComboBox), the approach will have to be more complicated, but considering the element is stored in the template of the control, something like this replaces the work that InitializeComponent does inside a UserControl:


[TemplatePart(Name = "PART_textbox", Type = typeof (TextBox))]
public class MyThemedControl : Control, ITextControl
{
private TextBox textbox;

public override void OnApplyTemplate()
{
base.OnApplyTemplate();
textbox = Template.FindName("PART_textbox", this) as TextBox;
}
...


The code is pretty straight forward: use the FrameworkTemplate.FindName method to find the elements in the OnApplyTemplate override and remember them as fields that you can access. The only weird part is the use of the TemplatePartAttribute, which is not mandatory for this to work, but is part of a pattern recommended by Microsoft. Possibly in the future tools will check for the existence of named elements in the templates and compare them against the ones declared in the control source.

The code of a demo project can be downloaded here.

Some other technologies I have used in the project:

  • the RelayCommand class, to make it easier to defined ICommand objects from code without declaring a type for each.
  • the AccessKeyScoper class that allows an IsDefault button to act locally in a panel.

If you google the net for using visual effects in WPF you are very likely to hit BitmapEffects. Well, bad news, BitmapEffect is obsolete and broken in WPF4. Instead you have Effect. The idea is to write (or download) a custom Effect for the things one would normally do using the slow (but easy to use) BitmapEffects. Also, the BitmapEffectGroup doesn't work anymore and has no alternative in WPF4. Bummer! According to Dr. WPF, the framework will try to automatically translate the older BitmapEffects to the new ones. That applies for BlurBitmapEffect and for DropShadowBitmapEffect with a Noise level of 0, for the others... you are on your own.

There were 5 default BitmapEffect classes in WPF3:
  1. BlurBitmapEffect - the WPF4 alternative is BlurEffect
  2. OuterGlowBitmapEffect - the WPF4 alternative in the Microsoft article is BlurEffect, but I have found that it can be replaced by DropShadowEffect with ShadowDepth set to 0
  3. DropShadowBitmapEffect - the WPF4 alternative is DropShadowEffect
  4. BevelBitmapEffect - the WPF4 alternative is a custom class inheriting from Effect.
  5. EmbossBitmapEffect - the WPF4 alternative is a custom class inheriting from Effect.


I found this project when googling to a simpler way of building ShaderEffects: WPF ShaderEffect Generator. Also, a discussion about a Bevel ShaderEffect here led me to this WPF shader library, but it's last release date is somewhere in March 2009.