Category Archives: Uncategorized

Solving cross-assembly WPF Resource problems once and for all

I wrote several posts about WPF weakness when it comes to sharing resources. Our use case, at my at work, where we load multiple versions of an assembly into a single app domain this problem has been felt most acutely. As I wrote previously, using the most documented way of loading resource dictionaries, unless you specify a version of an assembly when loading a resource dictionary you are running the risk of loading a wrong resource dictionary because you may have multiple versions of same library loaded into an app domain. And such problems are notoriously difficult to catch and understand.

At least now, it’s easy to solve. I am glad to announce that I found a definitive way to share resources across assembly boundaries without running into versioning issues. The key to doing this is to never load resource dictionary from another assembly using cross-assembly Uris. I did not know that there was another way until recently. All the examples of loading resource dictionaries, that I can recall, use the Source=”{PackUri}” method of loading, but there’s a way to reference resource dictionary using code.

A ResourceDictionary, just like any other class that can be defined in Xaml, can also contain the “code behind” portion, a source code file associated with the main Xaml file. If you already have resources defined in a resource dictionary somewhere in your assembly, you don’t have to change it. Instead you’ll create a brand new resource dictionary which you would use to export the resource for sharing. For example, let’s say you have a resource dictionary defining the colors of the stoplight. It lives in an assembly called ResourceSharing, in a namespace ResourceSharing.Resources in a file called Resources.xaml.


<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    
    <SolidColorBrush x:Key="Go" Color="Green"/>
    <SolidColorBrush x:Key="Stop" Color="Red"/>
    <SolidColorBrush x:Key="PrepareToStop" Color="Yellow"/>
    
</ResourceDictionary>

To export this ResourceDictionary, create a new Resource Dictionary for export. Let’s call it ResourceSharing.Resources.ExportResourceDictionary. I’ll consist of the xaml and the C# portions

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
                    x:Class="ResourceSharing.Resources.ExportResourceDictionary"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    
    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="Resources.xaml"/>
    </ResourceDictionary.MergedDictionaries>
    
</ResourceDictionary>

Notice the Class definition on line 2.

The code behind class looks like this

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ResourceSharing.Resources
{
    public partial class ExportResourceDictionary
    {
        //Expose it as singleton to avoid multiple instances of this dictionary
        private static readonly ExportResourceDictionary _instance = new ExportResourceDictionary();

        public static ExportResourceDictionary Instance
        {
            get { return _instance; }
        }

        public ExportResourceDictionary()
        {
            InitializeComponent();
        }
    }
}

Let’s also create a namespace we can use to make it easier to reference these resources from another assembly using namespaces

using System.Windows.Markup;

[assembly:XmlnsDefinitionAttribute("http://my.schemas.com/web/resources", "ResourceSharing.Resources")]

How to Share

Here’s how to consume the resources exported from the ResourceSharingAssembly. For this example, I had an executable assembly called ResourceSharingClient, where I am referencing exported resource right in the Main Window. Notice the use of the exported namespaces in line 2 and the way that I am referencing a static instance of the ExportResourceDictionary. Such references are version-proof because .NET knows the version of the dependent assemblies. There’s no need to dynamically discover the dependent assembly and the code actually looks a lot neater too. I know that such approach requires a bit more work, but the final result is a lot safer. I only wished that such approach had been advertised by Microsoft WPF evangelists from the beginning.

<Window
        x:Class="ResourceSharingClient.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:rs="http://my.schemas.com/web/resources"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
        mc:Ignorable="d"
        Title="MainWindow" d:DesignWidth="111.5" d:DesignHeight="109.5" Width="120" Height="130">
    <Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <x:Static Member="rs:ExportResourceDictionary.Instance"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>
    <Border BorderBrush="Black" BorderThickness="2" HorizontalAlignment="Center" VerticalAlignment="Center" Padding="2" CornerRadius="2" Background="Silver">
        <StackPanel Orientation="Vertical">
            <Ellipse Width="20" Height="20" Fill="{DynamicResource Stop}" Stroke="Black" StrokeThickness="1"/>
            <Ellipse Width="20" Height="20" Fill="{DynamicResource PrepareToStop}" Stroke="Black" StrokeThickness="1"/>
            <Ellipse Width="20" Height="20" Fill="{DynamicResource Go}"  Stroke="Black" StrokeThickness="1"/>
        </StackPanel>
    </Border>
</Window>
Advertisements

ASUS Product Support is Crap (continued)

Last Friday, I took a day to do run some errands and to tie up some lose ends including the old ASUS laptop that was returned to be the 3rd time, still broken.  As you may recall, from the previous post (https://alexfeinberg.wordpress.com/2015/02/07/asus-is-crap/), I was sending the laptop back to them the 3rd time after having it returned to me in the original broken condition 2 times.  Well, 3 times was *not* the charm for me.

Since I bought the laptop at Costco, I thought of using their Costco Concierge service to attempt to return the defective laptop back to them, but the best they could do for me was to contact ASUS to resolve it.  So back on the phone with ASUS, their customer service manager could, again, only offer me to have it sent in to them, but this time, he would request a replacement.  Progress?  Maybe.  He stressed to me that there is no guarantee that the laptop would be replaced, but at least he would initiate the process.  He also offered me an overnight shipping to them this time around.  Probably another benefit of having Costco on the phone with me.

In addition, I tweeted about my experience and to @ASUSUSA , who replied, offering to help:

asustweet

So I mustered confidence to finally send it in the 4th time.  Needless to say, I was very skeptical and unfortunately, a little pessimist in me turned out to be correct.

They received the laptop on Monday, the 20th of April 2015.  On Tuesday, the 21st, I decided to check the status.  This is what it looked like:

asusstatus

On one hand, the word swap was now appearing in the status, a positive indicator that they are, indeed, looking to replace the laptop with another one. But, it also said something about waiting on the customer confirmation…  Hmm… Confimation of what?    I had to call to find out.

The tech on the other end politely put me on hold and spent a good 5 mins figuring out what that meant.  He came back and told me that I should have gotten an email asking me to confirm the specs of the proposed replacement.  Needless to say, I had not gotten such email.  I mentioned it to him, but he promised that it would come in 24 hours.

On Wednesday afternoon, a day after speaking with the tech, and after checking my spam folders and finding no email from ASUS, I decided to call them again.   They could not help me, because their manager could not access the system for some reason and they did not want to do a 3-way call with me.  They insisted in calling me back within 24 hours.  I even tried to go the Costco Concierge route, but those guys are beginning to sense a losing battle as well and starting to disengage from this toxic case.  They too said to wait a day.

Well, there’s always tomorrow, right?  As of right now, I don’t even have the broken laptop until I confirm an email that I never received.  Back to twitter I go.

Solving the WPF Resource Key Collision

In my previous post about WPF Resource Keys, I talked about how WPF handles resource resolution when multiple resources with same key end up in loaded into same ResourceDictionary via merging.  In this post, I will present a solution.

So, apparently, Microsoft thought about it and provided a solution in a form of a class class called System.Windows.ComponentResourceKey.  This class is derives from a base class called System.Windows.ResourceKey, which is used inside the WPF resource resolution code.

So what does it do and how does work?

Normally, the WPF resource resolution logic assumes that all keys are objects used to identify resources in a ResourceDictionary.  Unlike a regular dictionary, a ResourceDictionary, technically, supports having multiple resources added with same key, but during the lookup operation, only the last resource added for a specific key will be returned.  So during the ‘merge’ operation, the new resources will overlay the existing ones if the keys clash, and during the ‘unmerge’ operation (ResourceDIctionary.MergedDictionaries.Remove()) the previously covered resource will emerge as ‘active’, so all the resources referenced via DynamicResouce will update.

The above gets more interesting if the key is of type System.Windows.ResourceKey.  If so, the resource resolution logic will only look at the resources which live in a dictionaries defined in the assembly referenced by the ResouceKey.  Moreover, when such set of dictionaries is found, the instance of the key is compared against other instances of the key to see if there’s a match, and because the System.Windows.ComponentResourceKey class overrides Equals and GetHashCode, the rules of equality take into consideration a bunch of parts, not just string value.

Here’s the code of the Equals and GetHashCode methods:

public override bool Equals(object o)
{
    var componentResourceKey = o as ComponentResourceKey;
    if (componentResourceKey == null)
    {
        return false;
    }
    // Ether neither objects define the TypeInTargetAssembly, 
    // or if both are defined, then make sure they are same
    if (!((componentResourceKey._typeInTargetAssembly != null) ? 
              componentResourceKey._typeInTargetAssembly.Equals(this._typeInTargetAssembly) :
             (this._typeInTargetAssembly == null)))
    {
        return false;
    }
    //If resourceId is null make sure they are both null
    if (componentResourceKey._resourceId == null)
    {
        return this._resourceId == null;
    }
    //otherwise do a simple equals
    return componentResourceKey._resourceId.Equals(this._resourceId);
}

public override int GetHashCode()
{  
   //use both, the type and the resouceid to generate a complex hashcode
   return ((this._typeInTargetAssembly != null) ? this._typeInTargetAssembly.GetHashCode() : 0) 
               ^ ((this._resourceId != null) ? this._resourceId.GetHashCode() : 0);
}

So when creating a reusable WPF component make sure you use the ComponentResourceKey class for your resource keys, do not just use strings and, obviously, refer to such resources using the ComponentResourceKey as well.  You can designate a single marker type (an empty public class) that lives in your assembly as a TypeInTargetAssembly to make it easier to reference your assembly when both, defining and referencing a resource.  This StackOverflow question showcases the use: http://stackoverflow.com/questions/337803/how-do-i-get-the-actual-resource-from-a-componentresourcekey.


//Exposing
public class Resources
{
    public static ComponentResourceKey BaseControlStyleKey
    {
        get
        {
            return new ComponentResourceKey(typeof(Resources), "BaseControlStyle");
        }
    }
}


//Using
myTextBox.Style = 
        Application.Current.TryFindResource(Resources.BaseControlStyleKey)
        as Style;



<!--Exposing -->
<Style x:Key="{ComponentResourceKey TypeInTargetAssembly={x:Type local:Resources}, ResourceId=BaseControlStyle}" TargetType="{x:Type FrameworkElement}">
    <Setter Property="Margin" Value="4,4,0,0" />
</Style>

<!-- Using -->
<TextBlock Style="{DynamicResource {ComponentResourceKey TypeInTargetAssembly={x:Type local:Resources}, ResourceId=BaseControlStyle}}"/>

<!-- Using in xaml by relying on the static property defined above -->
<TextBlock Style="{DynamicResource {x:Static local:Resources.BaseControlStyleKey}}"/>

WPF Resource Key Collision

Our framework allows developers to create add-ins (modules), which are loaded at run time.  It’s possible for each developer to create custom resources and merge them into a Resource Dictionary on the Application object.  So what happens when two different add-ins define a resource with the same key?  How does WPF handle such key collision?

To answer this question, II created a small application which tests the ability of a single resource dictionary to load multiple merged dictionaries which have objects with same key. The code is below but I did discover that

  1. the app does not crash – WPF handles redifinition of the key gracefully
  2. the last one wins – whichever dictionary defining the entry with the same key loads last is the one that’s going to be resolved when app asks for such resource using the DynamicResource
  3. the original definition becomes effective when the override is removed – removing the duplicate definition makes the original value effective

It’s important to note that if the key already exists in the primary dictionary, the one into which other dictionaries are merged, the discovery rules will ignore any re-definition of the key, according to docs here.

Resources in a merged dictionary occupy a location in the resource lookup scope that is just after the scope of the main resource dictionary they are merged into. Although a resource key must be unique within any individual dictionary, a key can exist multiple times in a set of merged dictionaries. In this case, the resource that is returned will come from the last dictionary found sequentially in the MergedDictionaries collection. If the MergedDictionaries collection was defined in XAML, then the order of the merged dictionaries in the collection is the order of the elements as provided in the markup. If a key is defined in the primary dictionary and also in a dictionary that was merged, then the resource that is returned will come from the primary dictionary. These scoping rules apply equally for both static resource references and dynamic resource references.

<Application x:Class="Test.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="rd1.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:sys="clr-namespace:System;assembly=mscorlib"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    
    <sys:String x:Key="MyString">Hello</sys:String>
    
</ResourceDictionary>
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:sys="clr-namespace:System;assembly=mscorlib"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    
    <sys:String x:Key="MyString">Hello</sys:String>
    
</ResourceDictionary>
<Window x:Class="Test.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>
        <Button Click="HandleClick" Content="{DynamicResource MyString}"/>
    </Grid>
</Window>
using System;
using System.Windows;

namespace Test
{
    public partial class MainWindow : Window
    {
        private bool _remove;
        public MainWindow()
        {
            InitializeComponent();
        }

        private void HandleClick(object sender, RoutedEventArgs e)
        {
            if (_remove)
                Application.Current.Resources.MergedDictionaries.Remove(Application.Current.Resources.MergedDictionaries[1]);
            else
                Application.Current.Resources.MergedDictionaries.Add(new ResourceDictionary() { Source = new Uri("rd2.xaml", UriKind.Relative) });

            _remove = !_remove;
        }
    }
}

Am I smarter than the fifth grader?

I thought I was, until my 10 year-old brought home a math homework from her school asking her to solve a few problems that look like this:

Replace letters with digits from this list [1, 2, 3, 4, 5, 7, 8, 9]
All letters to digit mapping is unique

   CAN
x  SAY
======
 BRAND

I thought such problem would have a quick-and-easy solution, like any others in a 5th grade math, but I was stumped. I tried several tricks to see if there was a shortcut to solving these, but found nothing. The only way to solve a problem like this was to iteratively try out various number combinations to see if the result would match the constraints of the problem.

Constraints

In a problem above the constraints are as follows:

  1. 2nd digit in the 2nd number must match 2nd digit in the 1st number
  2. 2nd and 3rd digit in the 1st number must match 3rd digit and 4th digits result
  3. Result must have 5 digits
  4. None of the digits of the result except for the 3rd and 4th can be present in the first two numbers

Solving such problem.

I learned that the type of these problems are called cryptarithms or verbal arithmetic. There’s a wikipedia page dedicated to these problems as well as a laundry list of sites hosting examples and explanations to these. There is no simple solution to such problem. The solution to them is defined as having NP-Complete in its difficulty, which according to Wikipedia is

In computational complexity theory, a decision problem is NP-complete when it is both in NP and NP-hard. The set of NP-complete problems is often denoted by NP-C or NPC. The abbreviation NP refers to “nondeterministic polynomial time”.

Although any given solution to an NP-complete problem can be verified quickly (in polynomial time), there is no known efficient way to locate a solution in the first place; indeed, the most notable characteristic of NP-complete problems is that no fast solution to them is known.

My Solution

The only way to solve it was to write a program, which I did below. I figured that I have to start with a basic mapping of letters to digits and “increment” the mapping by “1” at every iteration. The difficult part was to implement the “increment” because no two letters can be mapped to the single digit, I could not completely mimic the way we increment regular numbers in base 10. Plus the universe of digits can also be constrained if the problem creator chooses to do so.

The code is written in C#, and is lazy-coded, where the inputs are hard-coded in the main method, because I own the code and can easily change the definitions. It supports multiplication and addition. It managed to solve all the problems that I found online, so I am fairly confident that it works.

Perhaps I am still smarter than the 5th grader, even if slightly.

namespace WordMultiplication
{
    class Program
    {
        static void Main(string[] args)
        {
            var digits = new int[] { 1, 2, 3, 4, 5,  7, 8, 9 }.OrderBy(n => n).ToArray();
            var word1 = "CAN";
            var word2 = "SAY";
            var result = "BRAND";

            var orderedInputLetters = word1.Union(word2).Distinct().ToArray();
            if (orderedInputLetters.Length > digits.Length)
            {
                Console.WriteLine("More letters than digits!");
                return;
            }

            var numbersToLetterMap = new SortedDictionary<int, char?>();
            var lettersToNumbersMap = new Dictionary<char, int>();

            InitialSetup(orderedInputLetters, digits, numbersToLetterMap, lettersToNumbersMap);

            bool found;
            bool couldIncrement;
            do
            {
                couldIncrement = false;
                int number1 = GetNumberForWord(word1, lettersToNumbersMap);
                int number2 = GetNumberForWord(word2, lettersToNumbersMap);

                var mathResult = number1 * number2;

                found = number1.ToString().Length == word1.Length &&
                        number2.ToString().Length == word2.Length &&
                        Verify(mathResult, result, word1, word2, new Dictionary<char, int>(lettersToNumbersMap), digits);
                if (found)
                    Console.WriteLine("{0} x {1} = {2}", number1, number2, mathResult);
                else
                    couldIncrement = TryIncrement(orderedInputLetters.Length - 1, orderedInputLetters, digits, numbersToLetterMap, lettersToNumbersMap);


            } while (!found && couldIncrement);

            if (!found)
                Console.WriteLine("Result not found");
        }

        private static bool TryIncrement(int index, char[] inputLetters, int[] digits,
            IDictionary<int, char?> numbersToLetterMap, IDictionary<char, int> lettersToNumbersMap)
        {
            if (index == -1)
                return false;

            var currLetter = inputLetters[index];
            var currDigit = lettersToNumbersMap[currLetter];

            int nextDigit;
            //If we reached the end
            if (!numbersToLetterMap.Any(kvp => kvp.Key > currDigit && !kvp.Value.HasValue))
            {
                //put current letter aside
                numbersToLetterMap[currDigit] = null;
                lettersToNumbersMap[currLetter] = -1;

                //Try to increment a digit of higher significance
                if (TryIncrement(index - 1, inputLetters, digits, numbersToLetterMap, lettersToNumbersMap))
                    //If succeeded, find the first available empty spot for the current letter
                    nextDigit = numbersToLetterMap.First(kvp => !kvp.Value.HasValue).Key;
                else
                    return false;
            }
            else
            {
                numbersToLetterMap[currDigit] = null;
                nextDigit = numbersToLetterMap.First(kvp => kvp.Key > currDigit && !kvp.Value.HasValue).Key;
            }

            numbersToLetterMap[nextDigit] = currLetter;
            lettersToNumbersMap[currLetter] = nextDigit;

            return true;
        }


        private static void InitialSetup(char[] inputLetters, int[] digits, IDictionary<int, char?> numbersToLetterMap, IDictionary<char, int> lettersToNumbersMap)
        {
            foreach (var digit in digits)
                numbersToLetterMap[digit] = null;

            foreach (var c in inputLetters)
                lettersToNumbersMap[c] = -1;

            //Place letters in the beginning of the digit line
            for (int i = 0; i < inputLetters.Length; i++)
            {
                lettersToNumbersMap[inputLetters[i]] = digits[i];
                numbersToLetterMap[digits[i]] = inputLetters[i];
            }
        }

        private static bool Verify(int mathResult, string result, string word1, string word2, IDictionary<char, int> allletters, int[] digits)
        {
            if (mathResult.ToString().Length != result.Length)
                return false;

            for (int i = 0; i < result.Length; i++)
            {
                var resultChar = result[i];
                var digitForChar = (mathResult / (int)Math.Pow(10, result.Length - i - 1) % 10);
                
                //Can result be even used?
                if (Array.IndexOf(digits, digitForChar) == -1)
                    return false;

                if (allletters.Keys.Contains(resultChar))
                {
                    if (allletters[resultChar] != digitForChar)
                        return false;
                }
                else if (allletters.Values.Contains(digitForChar))
                {
                    if (allletters.First(kvp => kvp.Value == digitForChar).Key != resultChar)
                        return false;
                }
                else
                {
                    allletters[resultChar] = digitForChar;
                }
            }

            return true;

        }

        private static int GetNumberForWord(string word, IDictionary<char, int> allletters)
        {
            var number = 0;
            for (int i = 0; i < word.Length; i++)
            {
                number += allletters[word[i]] * (int)Math.Pow(10, (word.Length) - i - 1);
            }

            return number;
        }
    }
}

How to customize column headings in DevExpress WPF GridControl

DevExpress is one of several 3rd party .NET control providers offering a full suite of controls for WPF.  Their library of widgets is widely used in many financial firms to speed up time to market and make UI development easier.  They look good and work relatively well.  But I don’t want to advertize them too much here. If you are working with their GridControl, you probably noticed how notoriously difficult it is to certain things you thought should be a lot easier.

I recently was asked to color the background of the Grid Headers and decided I would share my pain and the solution here. Unfortunately, this exercise is not for the faint-hearted, as it requires switching your WPF project to use a custom theme that you will create using their tool.

I will show how you can modify their grid’s column heading template to inject your own Attached Properties which you can then set in your Xaml. But first, you will need to switch to a custom theme which you will create using the DevEpxress Theme Editor, which you can download here: https://www.devexpress.com/Products/NET/Controls/WPF/Themes/theme-editor.xml. You can read instructions on using the tool here: https://documentation.devexpress.com/#WpfThemeEditor/CustomDocument10429. If you use their skins already then pick those that you use as a base when saving your own custom theme. Once you have your own custom theme project, and are successfully using it in your project, you are ready to proceed with the advanced part of this exercise.

Here’s an overview of what you will need to do.

  • Step 1. Create another dll project where you would define your own custom attached properties. YOu will need to compile the project and generate a DLL which you will later reference
  • Step 2. Open the theme projects that the DevExpress tool generated in Visual Studio and add references to the dll you created in step 1.
  • Step 3. Modify their Grid Header XAML templates to reference your new Attached Properties.
  • Step 4. Reference dll you had created in step 1 in your projects and set the Attached Properties you created in the GridColumn definitions.

DevExpress wants you to use 3 different brushes to color Grid Column Headers:

1. Normal Background Brush: used for normal state rendering
2. Hover Over Brush: used when mouse is over the column heading
3. Mouse Click Brush: used when mouse is clicked while over the column heading

To encapsulate all 3 states, we are going to create a custom Type called GridColHeaderBrushes in our custom dll project (step 1). I’ll be a DependencyObject defining 3 Attached properties.
Here’s the code.


    public class GridColHeaderBrushes : DependencyObject
    {
        public static readonly DependencyProperty BackgroundProperty =
            DependencyProperty.RegisterAttached("Background",
            typeof(Brush),
            typeof(GridColHeaderBrushes),
            new UIPropertyMetadata(null));

        public static readonly DependencyProperty MouseOverProperty =
            DependencyProperty.RegisterAttached("MouseOver",
            typeof(Brush),
            typeof(GridColHeaderBrushes),
            new UIPropertyMetadata(null));

        public static readonly DependencyProperty MousePressedProperty =
            DependencyProperty.RegisterAttached("MousePressed",
            typeof(Brush),
            typeof(GridColHeaderBrushes),
            new UIPropertyMetadata(null));

        public Brush Background
        {
            get { return (Brush)GetValue(BackgroundProperty); }
            set { SetValue(BackgroundProperty, value); }
        }

        public Brush MouseOver
        {
            get { return (Brush)GetValue(MouseOverProperty); }
            set { SetValue(MouseOverProperty, value); }
        }

        public Brush MousePressed
        {
            get { return (Brush)GetValue(MousePressedProperty); }
            set { SetValue(MousePressedProperty, value); }
        }
    }

In addition we would need to create another class which would contain attached properties we would use on the grid. The two files must be in the same namespace to simplify things. Notice that I also added 2 more properties to control text alignment in column headers. This is a bonus 🙂

    public static class GridColumnHeaders
    {
        public static readonly DependencyProperty HeaderBackgroundsProperty =
            DependencyProperty.RegisterAttached("HeaderBackgrounds",
            typeof(GridColHeaderBrushes),
            typeof(GridColumnHeaders));

        public static readonly DependencyProperty HorizontalHeaderAlignmentProperty =
            DependencyProperty.RegisterAttached("HorizontalHeaderAlignment",
            typeof(HorizontalAlignment),
            typeof(GridColumnHeaders));

        public static readonly DependencyProperty VerticalHeaderAlignmentProperty =
            DependencyProperty.RegisterAttached("VerticalHeaderAlignment",
            typeof(VerticalAlignment),
            typeof(GridColumnHeaders));


        public static HorizontalAlignment GetHorizontalHeaderAlignment(DependencyObject obj)
        {
            return (HorizontalAlignment)obj.GetValue(HorizontalHeaderAlignmentProperty);
        }

        public static void SetHorizontalHeaderAlignment(DependencyObject obj, HorizontalAlignment value)
        {
            obj.SetValue(HorizontalHeaderAlignmentProperty, value);
        }

        public static VerticalAlignment GetVerticalHeaderAlignment(DependencyObject obj)
        {
            return (VerticalAlignment)obj.GetValue(VerticalHeaderAlignmentProperty);
        }

        public static void SetVerticalHeaderAlignment(DependencyObject obj, VerticalAlignment value)
        {
            obj.SetValue(VerticalHeaderAlignmentProperty, value);
        }

        public static GridColHeaderBrushes GetHeaderBackgrounds(DependencyObject obj)
        {
            return (GridColHeaderBrushes)obj.GetValue(HeaderBackgroundsProperty);
        }

        public static void SetHeaderBackgrounds(DependencyObject obj, GridColHeaderBrushes value)
        {
            obj.SetValue(HeaderBackgroundsProperty, value);
        }
    }

After you compile the dll, place it somewhere near the custom theme projects that DevExpress tool created for you, then open the custom theme project in Visual Studio. Open the regular project first – the one without the “ThemeEditor” in its name.

You will need to modify the ColumnHeader.xaml file located under the folder that matches your custom theme name, not under the “Generic” folder. You will need to do the following:

  1. Add a namespace reference to the namespace containing the classes above:
    <ResourceDictionary ... 
       xmlns:customui="clr-namespace:YourCustomAssembly.Namespace;assembly=YourCustomAssembly"/>
    
  2. Find the Border classes which are used as backgrounds for grid headers. They are named
    • BackgroundBorder
    • MouseOverElement
    • MousePressedElement

    and modify their “Background” Property so they look like this below. Make sure that you replace the with the hard-coded color that was in the code before you changed it.

    <Border x:Name="BackgroundBorder" Background="{Binding Path=(dxg:BaseGridColumnHeader.GridColumn).(customui:GridColumnHeaders.HeaderBackgrounds).Background, RelativeSource={RelativeSource TemplatedParent}, FallbackValue=<what was here before>}" cs:Name="Border_0004" />
    <Border x:Name="MouseOverElement" Background="{Binding Path=(dxg:BaseGridColumnHeader.GridColumn).(customui:GridColumnHeaders.HeaderBackgrounds).MouseOver, RelativeSource={RelativeSource TemplatedParent}, FallbackValue=<what was here before>}" Opacity="0" cs:Name="Border_0005" />
    <Border x:Name="MousePressedElement" Background="{Binding Path=(dxg:BaseGridColumnHeader.GridColumn).(customui:GridColumnHeaders.HeaderBackgrounds).MousePressed, RelativeSource={RelativeSource TemplatedParent}, FallbackValue=<what was here before>}" Opacity="0" cs:Name="Border_0006" /> 	
    
  3. As a bonus, add the HorizontalAlignment and VerticalAlignment properties to the Grid called “PART_Content” so it looks like this:
    <Grid x:Name="PART_Content"
      HorizontalAlignment="{Binding Path=(dxg:BaseGridColumnHeader.GridColumn).(customui:GridColumnHeaders.HorizontalHeaderAlignment), Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}, FallbackValue=Left}"
      VerticalAlignment="{Binding Path=(dxg:BaseGridColumnHeader.GridColumn).(customui:GridColumnHeaders.VerticalHeaderAlignment), Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}, FallbackValue=Center}" >
    
  4. Compile and Save the project
  5. Replace the original dll that the DevExpress Theme Editor had created for your project with the new version you just compiled.

Customizing Grid Column Headers

You will need to reference the your custom dll containing the new Attached Properties in your project as well.  Once you do, you are ready to set the colors and alghment of your grid column headings. Don’t forget to add a customui namespace declaration at the top of your xaml file.

Here’s an example:

<dxg:GridControl ...>
 <dxg.GridControl.Columns>
   <dxg.GridColumn...>
      <customui:GridColumnHeaders.HeaderBackgrounds>
           <customui:DrigColHeaderBrushes Background="White" MouseOver="Green" MousePressed="Orange"/>
      </customui:GridColumnHeaders.HeaderBackgrounds>
   </dxg.GridColumn>
  ...

To control alignment you can do this:

<dxg:GridControl ...>
 <dxg.GridControl.Columns>
   <dxg.GridColumn customui:GridColumnHeaders.HorizontalHeaderAlignment="Right".../>
  ...