How can I get my UserControl to look like a ComboBox?
I have a user control containing a TextBox, ToggleButton and Popup, just like the real ComboBox. Now my problem is to style it so that it looks just like the normal ComboBox开发者_开发知识库.
In Blend, I can "Edit Template/Edit a Copy..." of a real ComboBox to get the bits and pieces I need to get it to look right. For one Windows theme (Aero). If the application is run on another theme (e.g Luna), the control does not change its look, it still has the Aero look.
Do I have to supply a style/template for each Windows theme, or can I somehow get hold of (at run-time) the default ComboBox style and apply it to my UserControl?
Instead of making a UserControl, I have tried modifying a real ComboBox to my needs, but I just couldn't get it to work. How can I replace ALL the logic of a ComboBox with my own?
Taking advantage of Windows themes would be one way to approach this. Most of this is paraphrased and truncated from Windows Presentation Foundation Unleashed by Adam Nathan.
Simple Approach
You could use the resources and keys exposed by SystemColors
, SystemFonts
, and SystemParameters
in your control template (along with DynamicResource
, in case the theme is changed while your program is running) to set the appropriate values:
Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"
Robust Approach
The better way, though it requires more work, is to have a control template for each theme rather than one set that overrides everything. The way you do this is to put all your theme-specific resources into their own resource dictionary. These dictionaries are placed in a themes subfolder in the root of your project, and are each named after the theme name and theme color: ThemeName.ThemeColor.xaml.
Note that you still use SystemColors
, SystemFonts
, and SystemParameters
, as in the simple approach.
I don't have the newer edition of the book that probably lists Windows 7 themes, but here are the ones Adam lists in the edition I have:
- Vista Aero: themes\Aero.NormalColor.xaml
- XP default: themes\Luna.NormalColor.xaml
- XP green: themes\Luna.Homestead.xaml
- XP silver: themes\Luna.Metallic.xaml
- XP royale: themes\Royale.NormalColor.xaml
- XP Zune: themes\Zune.NormalColor.xaml
- Classic: themes\Classic.xaml
These will be automatically loaded, and switched out if the theme is changed. You can also specify themes\Generic.xaml as a default when it tries to load a theme that you haven't a created a resource dictionary to match.
You also have to opt-in to the automatic theming with ThemeInfoAttribute
:
//look inside this assembly
[assembly:ThemeInfo(ResourceDictionaryLocation.SourceAssembly,
ResourceDictionaryLocation.SourceAssembly)]
ResourceDictionaryLocation
also has an ExternalAssembly
option. The naming convention for these external assemblies is MainAssembly.ThemeName.dll, so if your assembly is called MyApp, it would look for the Classic theme resource dictionary in MyApp.Classic.dll.
And finally, you use ThemeDictionaryExtension
in you app resource dictionary:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="{ThemeDictionary MyApp}"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
If you make any custom controls that derive from another control (not UserControl
, but ProgressBar
, for example), you should do this in its static constructor:
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyControl),
new FrameworkPropertyMetadata(typeof(MyControl)));
精彩评论