Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <h1>Long Answer</h1> <p>The previous <a href="https://stackoverflow.com/questions/4239714/why-cant-i-style-a-control-with-the-aero-theme-applied-in-wpf-4-0/5471360#5471360">short answer</a> provides some XAML to remedy the problem as well as a brief summary of what's causing it. </p> <blockquote> <p><em>Loading a theme’s resources is not the same as changing the theme at the OS level. Loading a theme’s resources may cause adverse effects. From WPF’s point of view, a large number of implicit Styles are now present in the application. These Styles may trump other Styles. The bottom line is treating a theme like an application skin may not work without refinements.</em></p> </blockquote> <p>The following long answer will provide a more in-depth discussion of the problem. A few background topics will be covered first. This will answer some of the peripheral questions asked and it will also provide a better basis for understanding the issues at hand. After that, individual aspects of the problem will be dissected and addressed with an effective debugging strategy.</p> <h2>Theme Versus Skin</h2> <p>This was great question partly because hundreds of bloggers and forum threads recommend loading a theme from file as a way of “changing your theme”. Some of the authors making this recommendation work at Microsoft and many of the authors are obviously high caliber software engineers. This approach <em>appears</em> to work much of the time. However, as you noticed, this approach didn’t exactly work in your scenario and required a number of refinements.</p> <p>Some of this problem stems from imprecise terminology. Unfortunately, the word theme has become hopelessly overloaded. A precise definition for theme that would avoid confusion is simply <em>the system theme</em>. A <a href="http://msdn.microsoft.com/en-us/library/bb773190%28v=vs.85%29.aspx" rel="nofollow noreferrer">system theme</a> defines the default appearance of Win32 visuals on the machine. My OS is Vista. My installed themes are located at C:\WINDOWS\Resources\Themes. In that folder are two files: aero.theme and Windows Classic.theme. If I want to change the theme I go to either [Personalize | Theme] or [Personalize | Window Color and Appearance | Color scheme]. Although it's not immediately obvious, the options I can select from all boil down to either Aero or Classic plus some additional refinements. Because a WPF window renders its client area rather than compositing a bunch of Win32 controls, the client area will not automatically respect the theme. The theme assemblies (e.g. PresentationFramework.Aero.dll) provide a basis for extending theme functionality into WPF windows.</p> <p><img src="https://i.stack.imgur.com/9F5hV.png" alt="enter image description here"> <img src="https://i.stack.imgur.com/kuWF7.png" alt="enter image description here"></p> <p>The more general definition of theme is any look and feel configuration, at any level of granularity (OS, Application, Control). When people use the general definition, there is the potential for various degrees of confusion. Note that MSDN switches between the precise definition and the general definition without warning!</p> <p>Many people would say you were loading an application <em>skin</em>, not a theme. Either word is arguably correct, but I would recommend this mental model simply because it causes less confusion.</p> <blockquote> <p>So, how do I ensure that my app always uses the Aero <strong>theme</strong>…? [emphasis added]</p> </blockquote> <p>Again, it could be said you are loading Aero’s resources as a <em>skin</em>. Specifically, you’re loading the ResourceDictionary located inside PresentationFramework.Aero.dll. Those resources were previously given special treatment as they were default resources. However, once inside the application, they will be treated like any other arbitrary collection of resources. Of course, Aero’s ResourceDictionary is comprehensive. Since it will be loaded at the application scope, it will effectively hide every default Style provided by the theme (Luna, in your case), plus a few other Styles, which is causing the problem. Note that ultimately, the theme is still the same (Luna).</p> <p>As alluded to above, the theme is involved in <a href="http://msdn.microsoft.com/en-us/library/ms743230.aspx#style_property" rel="nofollow noreferrer">Style precedence</a>, which is itself a form of <a href="http://msdn.microsoft.com/en-us/library/ms743230.aspx#listing" rel="nofollow noreferrer">Dependency Property precedence</a>. These precedence rules greatly demystify the observed behavior in the problem. </p> <blockquote> <p><strong>Explicit style</strong>. The Style property is set directly. In most scenarios, the style is not defined inline, but instead is referenced as a resource, by explicit key…</p> <p><strong>Implicit style</strong>. The Style property is not set directly. However, the Style exists at some level in the resource lookup sequence (page, application) and is keyed using a resource key that matches the type the style is to be applied to…</p> <p><strong>Default style</strong>, also known as <strong>theme style</strong>. The Style property is not set directly, and in fact will read as null... In this case, the style comes from the run-time theme evaluation that is part of the WPF presentation engine.</p> </blockquote> <p>This <a href="http://www.interact-sw.co.uk/iangblog/2007/02/14/wpfdefaulttemplate" rel="nofollow noreferrer">blog entry</a> takes a much deeper look at style versus default style.</p> <h2>.NET Assembly Inspection</h2> <p>This was also a great question partly because there are so many moving parts. <em>Without an effective debugging strategy it will be almost impossible to understand what’s going on.</em> With that in mind, .NET assembly inspection is a natural place to start.</p> <p>From WPF’s point of view, a theme is essentially a ResourceDictionary serialized as BAML and embedded in a regular .NET assembly (e.g. PresentationFramework.Aero.dll). Later on, it will be necessary to view the themes as plain XAML to verify behavior in the problem. </p> <p>Fortunately, Microsoft provides the <a href="http://archive.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=wpfsamples&amp;DownloadId=7812" rel="nofollow noreferrer">4.0 themes</a> as XAML for developers’ convenience. I’m not sure if pre-4.0 themes are downloadable in any form from Microsoft.</p> <p>For general assemblies (including pre-4.0 theme assemblies), you can use the (previously free) tool <a href="http://www.reflector.net" rel="nofollow noreferrer">Reflector</a> with the <a href="http://reflectoraddins.codeplex.com/wikipage?title=BamlViewer" rel="nofollow noreferrer">BamlViewer plugin</a> to decompile the BAML back into XAML. Although not as flashy, <a href="http://wiki.sharpdevelop.net/ilspy.ashx" rel="nofollow noreferrer">ILSpy</a> is a free alternative with a built in BAML decompiler.</p> <p><img src="https://i.stack.imgur.com/UMdrQ.png" alt="enter image description here"></p> <p>.NET assemblies are littered throughout your hard drive and <a href="https://stackoverflow.com/questions/2851406/why-are-framework-dlls-repeated-in-several-places">it’s kind of confusing</a>. Here are their paths on my machine, which I sort of have a gut feeling for and sometimes manage to remember without trial and error.</p> <p>Aero 3.0</p> <p>C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0\PresentationFramework.Aero.dll</p> <p>Aero 4.0</p> <p>C:\WINDOWS\Microsoft.NET\assembly\GAC_MSIL\PresentationFramework.Aero\v4.0_4.0.0.0__31bf3856ad364e35\PresentationFramework.Aero.dll</p> <blockquote> <p>What is the PublicKeyToken for version 4 (or how do I figure this out)?</p> </blockquote> <p>The easiest thing to do is use Reflector. The PublicKeyToken is the same as before: 31bf3856ad364e35</p> <p><img src="https://i.stack.imgur.com/gc0OU.png" alt="enter image description here"></p> <p>Additionally, <a href="http://msdn.microsoft.com/en-us/library/k5b5tt23%28v=VS.100%29.aspx" rel="nofollow noreferrer">sn.exe</a> (from the Windows SDK) can extract assembly information. </p> <p>On my machine, the command is: </p> <p>C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin>sn.exe -Tp "C:\WINDOWS\Microsoft.NET\assembly\GAC_MSIL\PresentationFramework.Aero\v4.0_4.0.0.0__31bf3856ad364e35\PresentationFramework.Aero.dll"</p> <p><img src="https://i.stack.imgur.com/Ik8ju.png" alt="enter image description here"></p> <h2>Loading Themes as Skins</h2> <blockquote> <p>Should (the PresentationFramework.Aero reference) be updated to version 4.0?</p> </blockquote> <p>Most definitely. The DataGrid did not exist in the .NET FCL prior to 4.0. There are several ways to confirm this, but the most intuitive one is that, by your own admission, you previously accessed it via the WPF Toolkit. If you choose to not load PresentationFramework.Aero 4.0 in App.xaml, Aero’s DataGrid Style won’t be in the application resources.</p> <p>Now, it turns out it doesn’t even matter. I’ll use the original XAML, break in the debugger when loading, and inspect the application-scoped resources.</p> <p><img src="https://i.stack.imgur.com/dqZBr.png" alt="enter image description here"></p> <p>As expected, there are two ResourceDictionaries in the application’s MergedDictionaries property, and the first ResourceDictionary is allegedly the 3.0 version of PresentationFramework.Aero. However, I see there are <em>266</em> resources in the first ResourceDictionary. At this point, it just so happens I know there are 266 resources in the Aero 4.0 theme, and only 243 resources in the Aero 3.0 theme. Moreover, there’s even a DataGrid entry! This ResourceDictionary is, in fact, the Aero 4.0 ResourceDictionary.</p> <p>Perhaps someone else can explain why WPF is loading the 4.0 assembly when 3.0 was explicitly specified. What I can tell you is if the projects are retargeted to .NET 3.0 (and the compile errors are fixed), the 3.0 version of Aero will be loaded instead. </p> <p><img src="https://i.stack.imgur.com/ZxljA.png" alt="enter image description here"> <img src="https://i.stack.imgur.com/VFoyk.png" alt="enter image description here"></p> <p>As you correctly deduced, Aero 4.0 should be loaded anyway. It’s just useful to know what’s going on while debugging this.</p> <p> </p> <h2>Problem #1: Aero’s DataGrid Style is not Being Used</h2> <p>The DataGrid in this application will have zero or more Styles chained together depending on how you configure Style.BasedOn properties. </p> <p>It will also have a default Style, which, in your case, is embedded in the Luna theme.</p> <p>I knew just by looking at the original XAML there was a Style inheritance issue. The big DataGrid Style with ~20 Setters does not set its BasedOn property.</p> <p><img src="https://i.stack.imgur.com/4ghGu.png" alt="enter image description here"></p> <p>You have a Style chain of length two and your default Style is from the Luna theme. The DataGrid Style in Aero’s ResourceDictionary is simply not being used. </p> <p>There are two big questions here. First, how can something like this be debugged in the first place? Second, what are the implications?</p> <p> </p> <h2>Debugging Style Chains</h2> <p>I would recommend using <a href="http://snoopwpf.codeplex.com/" rel="nofollow noreferrer">Snoop</a> and/or <a href="http://wpfinspector.codeplex.com/" rel="nofollow noreferrer">WPF Inspector</a> to debug WPF issues like this.</p> <p>Version 0.9.9 of WPF Inspector even has a Style chain viewer. (I must warn you that this feature is currently buggy and not very useful for debugging this part of the application. Also note that it chooses to depict the default Style as part of the chain.)</p> <p>The power of these tools is their ability to view and edit values of <em>deeply nested</em> elements at <em>run-time</em>. You can simply mouse over an element and its information will immediately surface in the tool.</p> <p>Alternatively, if you simply want to look at a top-level element like the DataGrid, name the element in the XAML (e.g. x:Name="dg"), then break in the debugger when loading and put the element’s name in a Watch window. There you can inspect the Style chain via the BasedOn property.</p> <p>Below, I’ve broken in the debugger while using the solution XAML. The DataGrid has three Styles in the Style chain with 4, 17, and 9 Setters respectively. I can drill a little deeper and deduce the first Style is “DataGrid_FixedStyle”. As expected, the second is the large, <a href="http://msdn.microsoft.com/en-us/library/ms750613.aspx#stylesimplicitkeys" rel="nofollow noreferrer">implicit</a> DataGrid Style from the same file. Finally, the third Style appears to be from Aero’s ResourceDictionary. Note that the default Style is not represented in this chain.</p> <p><img src="https://i.stack.imgur.com/BfwUx.png" alt="enter image description here"></p> <p>At this point it should be noted that there is actually no variation between each theme's DataGrid Style. You can verify this by taking the DataGrid Styles from their respective <a href="http://archive.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=wpfsamples&amp;DownloadId=7812" rel="nofollow noreferrer">4.0 themes</a>, copying them into separate text files, and then comparing them with a diff tool. </p> <p>In fact, a moderate number of Styles are simply <em>identical</em> from theme to theme. This is good to be aware of. To verify this, simply run a diff on the entire XAML held in two different themes. </p> <p><img src="https://i.stack.imgur.com/YQ0av.png" alt="enter image description here"></p> <p>Note that there are many different elements nested within the DataGrid (e.g. DataGridRow) and each has its own Style. Even though DataGrid Styles are currently identical from theme to theme, the Styles for these nested elements could vary. Based on observed behavior in the problem, it's clear that some do.  </p> <h2>Implications of Original XAML not Incorporating Aero’s DataGrid Style</h2> <p>Since DataGrid Styles are identical across the 4.0 themes, adding Aero’s DataGrid Style to the end of the Style chain is, in this case, <em>basically</em> superfluous. Aero’s DataGrid Style will be the same as the default DataGrid Style (from Luna, in your case). Of course, future themes could always have variations with respect to the DataGrid Style.</p> <p>Regardless of whether there are any implications, since you intended to incorporate the Styles from Aero, it’s clearly more correct to do so until there’s a specific reason to not do so (which will be discussed later). </p> <p>Most importantly, it's just useful to know what's going on.</p> <h2>Style.BasedOn Only Has Meaning within the Context in which it’s Used</h2> <p>In the solution XAML, DataGridResourceDictionary.xaml works exactly the way you want it to work. It’s important to understand why, and it’s important to understand that using it this way precludes using it in other ways.</p> <p>Let’s say the final Styles in DataGridResourceDictionary.xaml’s Style chains set their BasedOn properties to a Type key (e.g. BasedOn="{StaticResource {x:Type DataGrid}}"). If they do that, then they will inherit from an implicit Style that matches this key. However, the Style that they inherit from depends on where DataGridResourceDictionary.xaml is loaded. If, for example, DataGridResourceDictionary.xaml is loaded into a merged dictionary right after Aero’s resources are loaded, then its Styles will inherit from the appropriate Aero Styles. Now, if, for example, DataGridResourceDictionary.xaml is the only ResourceDictionary loaded in the entire application, its Styles will actually inherit from the relevant Styles in the current theme (Luna, in your case). Note that the theme’s Styles will of course also be the default Styles!</p> <p><img src="https://i.stack.imgur.com/pjD64.png" alt="enter image description here"></p> <p>Now let’s say the final Styles in DataGridResourceDictionary.xaml’s Style chains <em>do not</em> set their BasedOn properties. If they do that, then they will be the final Styles in their respective Style chains, and the only other Styles evaluated will be the default Styles (always located in the theme). Note that this would kill your intended design of loading Aero as a skin and selectively refining parts of it.</p> <p>Note that in the previous examples, if the final key was a string (e.g. x:Key="MyStringKey") instead of a Type, the same sorts of things would happen, but there would not be any matching Styles in the themes or in the Aero skin. An Exception would be thrown at load time. That said, dangling string keys could theoretically work if a context always existed in which a matching Style was found.</p> <p>In the solution XAML, DataGridResourceDictionary.xaml has been modified. Styles at the end of each Style chain now inherit from an additional, implicit Style. When loaded in App.xaml, these will resolve to Aero Styles.</p> <h2>Problem #2: DataGrid.ColumnHeaderStyle and DataGrid.CellStyle</h2> <p><em>This is a nasty problem and it’s responsible for some of the strange behavior you saw. DataGrid.ColumnHeaderStyle and DataGrid.CellStyle get trumped by implicit DataGridColumnHeader and DataGridCell Styles. That is to say, they are incompatible with the Aero skin. Thus, they are simply removed from the solution XAML.</em> </p> <p>The rest of this subsection is a thorough investigation of the problem. DataGridColumnHeader and DataGridCell, like all FrameworkElements, have a Style property. In addition, there are a couple of very similar properties on DataGrid: ColumnHeaderStyle and CellStyle. You could call those two properties “helper properties”. They map, at least conceptually, to DataGridColumnHeader.Style and DataGridCell.Style. How they actually get used though is undocumented, so we must dig deeper.</p> <p>The properties DataGridColumnHeader.Style and DataGridCell.Style use <a href="http://msdn.microsoft.com/en-us/library/ms745795.aspx#Coerce_Value_Callbacks_and_Property_Changed_Events" rel="nofollow noreferrer">value coercion</a>. That means that when either Style is queried, special callbacks are used to determine what Style is actually returned to the caller (internal WPF code, for the most part). These callbacks can return <em>any</em> value they want. Ultimately, DataGrid.ColumnHeaderStyle and DataGrid.CellStyle are <em>candidate</em> return values in the respective callbacks. </p> <p>With Reflector I can easily determine all of this. (If necessary, it’s also possible to <a href="http://blogs.microsoft.co.il/blogs/arik/archive/2010/07/12/step-into-net-framework-4-0-source-code.aspx" rel="nofollow noreferrer">step through .NET source code</a>.) Starting in DataGridColumnHeader's static constructor, I locate the Style property and see it is being assigned additional metadata. Specifically, a coercion callback is specified. Beginning with that callback, I click through a sequence of method calls and quickly see what’s going on. (Note that DataGridCell does the same thing so I won't cover it.)</p> <p><img src="https://i.stack.imgur.com/SuCfq.png" alt="enter image description here"></p> <p>The final method, DataGridHelper.GetCoercedTransferPropertyValue, essentially compares the source of DataGridColumnHeader.Style and DataGrid.ColumnHeaderStyle. Whichever source has higher precedence wins. The precedence rules in this method are based on <a href="http://msdn.microsoft.com/en-us/library/ms743230.aspx#listing" rel="nofollow noreferrer">Dependency Property predecence</a>.</p> <p>At this point, DataGrid.ColumnHeaderStyle will be inspected in both the original XAML and the solution XAML. A small matrix of information will be collected. Ultimately, this will explain the observed behavior in each application.</p> <p>In the original XAML, I break in the debugger and see that DataGrid.ColumnHeaderStyle has a ‘Style’ source. This makes sense as it was set inside a Style.</p> <p><img src="https://i.stack.imgur.com/yDLi1.png" alt="enter image description here"> <img src="https://i.stack.imgur.com/zMmwN.png" alt="enter image description here"></p> <p>In the solution XAML, I break in the debugger and see that DataGrid.ColumnHeaderStyle has a ‘Default’ source. This makes sense as that value was not set in a Style (or anywhere else).</p> <p><img src="https://i.stack.imgur.com/KQFuB.png" alt="enter image description here"> <img src="https://i.stack.imgur.com/sE3yQ.png" alt="enter image description here"></p> <p>The other value to inspect is DataGridColumnHeader.Style. DataGridColumnHeader is a deeply nested element that isn’t conveniently accessible when debugging in VisualStudio. Realistically, a tool like Snoop or WPF Inspector would be used to inspect the property.</p> <p>With the original XAML, DataGridColumnHeader.Style has an ‘ImplicitStyleReference’ source. This makes sense. DataGridColumnHeaders are instantiated deep down in internal WPF code. Their Style property is null and so they will look for an implicit Style. The tree is traversed from the DataGridColumnHeader element to the root element. As expected, no Styles are found. Then the application resources are checked. You have a string key ("DataGrid_ColumnHeaderStyle") set on the lone DataGridColumnHeader Style. This effectively hides it in this lookup and so it isn’t used. Then, the Aero skin is searched and a typical implicit Style is found. This is the Style that is used.</p> <p><img src="https://i.stack.imgur.com/L2Uk6.png" alt="enter image description here"></p> <p>If this step is repeated with the solution XAML, the result is the same: 'ImplicitStyleReference'. This time, however, the implicit Style is the lone DataGridColumnHeader Style in DataGridResourceDictionary.xaml, now implicitly keyed.</p> <p><img src="https://i.stack.imgur.com/q6G2H.png" alt="enter image description here"></p> <p>Finally, if this step is repeated once again with the original XAML, <em>and the Aero skin is not loaded</em>, the result is now ‘Default’! This is because there are simply no implicit DataGridColumnHeader Styles in the entire application. </p> <p>Therefore, DataGrid.ColumnHeaderStyle will be used if the Aero skin is not loaded, but will not be used if the Aero skin is loaded! As advertised, <em>loading a theme's resources may cause adverse effects</em>.</p> <p>It’s a lot to keep straight and the names all sound the same. The following diagram recaps all the action. Remember, the property with the higher precedence wins.</p> <p><img src="https://i.stack.imgur.com/HFQr0.png" alt="enter image description here"></p> <p>It may not be what you want, but this is how the DataGrid works as of WPF 4.0. Taking this into account, you could theoretically set DataGrid.ColumnHeaderStyle and DataGrid.CellStyle at a very broad scope, and still have the ability to override the DataGridColumnHeader and DataGridCell Styles at a more narrow scope using implicit Styles.</p> <p><em>Again, DataGrid.ColumnHeaderStyle and DataGrid.CellStyle get trumped by implicit DataGridColumnHeader and DataGridCell Styles. That is to say, they are incompatible with the Aero skin. Thus, they are simply removed from the solution XAML.</em> </p> <h2>Problem #3: DataGridRow.Background</h2> <p>If the recommended changes up to this point have been implemented, something resembling the following should be on your screen. (Keep in mind I set my theme to Classic in order to debug this problem.)</p> <p><img src="https://i.stack.imgur.com/DQ8uV.png" alt="enter image description here"></p> <p>The DataGrid has an Aero look, but AlternatingRowBackground isn’t being respected. Every other row ought to have a gray background.</p> <p><img src="https://i.stack.imgur.com/MIrbc.png" alt="enter image description here"></p> <p>Using the debugging techniques discussed up to now, it will be found that <em>this is the exact same type of problem as Problem #2</em>. An implicit DataGridRow Style inside the Aero skin is now being loaded. DataGridRow.Background uses property coercion. DataGrid.AlternatingRowBackground is a <em>candidate</em> value that may be returned in the coercion callback. DataGridRow.Background is another <em>candidate</em>. <em>Where these values originate from will influence which value the coercion callback chooses</em>.</p> <p>By now it should be clear, but if not, it must be reiterated. <em>Loading a theme's resources may cause adverse effects.</em></p> <p>The short answer to this sub-problem is DataGridRow.Background must only be set in the theme. Specifically, it must not be set by a Style Setter anywhere in the application. Unfortunately, that’s now precisely what’s happening in the Aero skin. There are at least two ways to address this problem. </p> <p>A blank implicit Style can be added after the Aero skin. This hides the offending Style in Aero. There are no values in the blank Style so values from the default Style end up being used. In the end, this only works because DataGridRow Styles are identical in every 4.0 theme.</p> <p>Alternatively, Aero’s DataGridRow Style can be copied, the Background Setter can be removed, and the remainder of the Style can be added after the Aero skin. The solution XAML employs this technique. By expanding the Style out, the application is more likely to continue looking Aero in future scenarios. By isolating this expansion in App.xaml, DataGridResourceDictionary.xaml can be used more freely in other contexts. However, note that it may make more sense to add it to DataGridResourceDictionary.xaml, depending on how that file is used in the future. In terms of this application, either way works.</p> <h2>Problem #4: DataGridColumnHeader Layout</h2> <p>The final change is fairly superficial. If the application is run after making the recommended changes so far, the DataGridColumnHeaders will have content that is left-aligned rather than centered. This problem can be drilled into easily with Snoop or WPF Inspector. The root of the problem appears to be the DataGridColumnHeaders have <a href="http://msdn.microsoft.com/en-us/library/system.windows.controls.control.horizontalcontentalignment.aspx" rel="nofollow noreferrer">HorizontalContentAlignment</a> set to ‘Left’.</p> <p><img src="https://i.stack.imgur.com/9aYwD.png" alt="enter image description here"></p> <p>Set it to ‘Stretch’ and it works as expected.</p> <p>There’s some interplay between the <a href="http://msdn.microsoft.com/en-us/library/ms751709.aspx" rel="nofollow noreferrer">Layout properties</a> and <a href="http://msdn.microsoft.com/en-us/library/system.windows.controls.textblock.aspx" rel="nofollow noreferrer">TextBlock</a> formatting properties. Snoop and WPF Inspector allow for experimentation and make it easy to determine what works in any given situation.</p> <h2>Final Thoughts</h2> <p><em>To summarize, loading a theme’s resources is not the same as changing the theme at the OS level. Loading a theme’s resources may cause adverse effects. From WPF’s point of view, a large number of implicit Styles are now present in the application. These Styles may trump other Styles. The bottom line is treating a theme like an application skin may not work without refinements.</em></p> <p>That said, I’m not completely sold on the current WPF implementation with respect to "helper properties" (e.g. DataGrid.ColumnHeaderStyle) being used via a coercion callback with precedence rules. I have to wonder why they can’t just be locally assigned to their intended targets (e.g. DataGridColumnHeader.Style) at initialization time, if the targets do not already have an explicitly assigned value. I haven't thought enough about this to know what the various problems might be, but if it's possible, it might make the "helper property" model more intuitive, more consistent with other properties, and more foolproof.</p> <p>Finally, although it wasn’t the focus of this answer, it’s very important to note that loading a theme’s resources to simulate changing the theme is particularly bad because there is a <em>substantial maintainability cost</em>. Existing Styles in the application will not automatically be based on the Styles inside the theme’s ResourceDictionary. Each Style in the application would have to set its BasedOn property to a Type key (or be based, directly or indirectly, on another Style which does). This is extremely burdensome and error-prone. Additionally, there is a maintainability cost with respect to theme-aware custom controls. The <a href="http://msdn.microsoft.com/en-us/library/system.windows.themeinfoattribute.aspx" rel="nofollow noreferrer">theme resources</a> for these custom controls would also have to be loaded to effect this simulation. And of course, after doing that, you might face Style precedence issues similar to the ones you faced here!</p> <p>Anyway, there’s more than one way to skin a WPF app (no pun intended!). I hope this answer provides additional insight into your problem, and helps you and others solve similar problems.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
    1. CO+1 thank you! I finally had some time to sit down and read your long answer, and it was well worth it. Not all the details have sunk in yet, but I definitely have a feeling for why loading the resources for a theme is not equivalent to switching themes at the OS level. I should mention that I plan to abandon the practice of loading the Aero skin as soon as I upgrade to a Windows 7 laptop (which should be soon). In the meantime, though, I'll continue with my somewhat fragile setup, because I need to know how my app will look on Vista/Windows 7 machines.
      singulars
    2. CO*However, note that it may make more sense to add it to DataGridResourceDictionary.xaml, depending on how that file is used in the future. In terms of this application, either way works.* This is exactly what I decided to do when I first incorporated your solution into my code library.
      singulars
    3. COA final item that I don't think was directly addressed in your long answer is why my "original solution" used to work with the WPF Toolkit but stopped when I upgraded to WPF 4.0. Based on what I've learned so far, I'm guessing that it has something to do with the fact that the default theme doesn't have any resources pertaining to the Toolkit version of the DataGrid. In addition, I was explicitly loading the Aero skin for the WPF Toolkit. I can easily see how the style chain would be different in this setup. The resources may not be entirely equivalent either.
      singulars
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload