Retemplating a Button control with custom properties possible? - wpf

I made myself a TransparentButton style that makes the Button portion behave the way I want it to (mouseover, enabled, etc), but what I haven't been able to do is set the content correctly in the style. Currently, I manually set everything in <Button.Content> for every button, and clearly that stuff needs to go into the Style. I have set the ContentTemplate for the style to a StackPanel that just contains an Image and a Label. The problem is, I don't know how to specify in my <Button ...> markup the Label's text and the Image's Source. I figured that it had to do with TemplateBinding somehow, but I've been searching like crazy and can't seem to find the information.
So, in summary, I just want a consistent button style where the button content is just a StackPanel of an Image and a Label, and I want to be able to create it in my GUI with something simple like:
<Button Style={DynamicResource TransparentButton}"
Label="Click Me" Image="Images/MyImage.png" />
Any tips would be much appreciated! I hope I'm on the right track here...

In order to create custom properties like this, you'll need to make a CustomControl instead of just using a Button style.
This is fairly easy, though - just make a custom control that subclasses button, and adds your new properties (as dependency properties). This will make it stylable, but also provide you the ability to enforce that those properties are always available, with the syntax you're describing (other than changing <Button to <local:MyButton).
For details, see the Control Authoring Overview on MSDN.

Related

Subclassing WPF control themes, why not only PARTIAL subclass

So much reading, and so much about inheritance, I can't find any direct answers, so here goes.
If you have a base-class derived to do certain things, look or act a certain way, you can subclass it and get all the functionality of the parent class with only slightly modified differential. The same does not appear to be the same for working with WPF Themes... more specifically, the combobox control (similar issues with textbox, but that's obviously less complex).
By looking at the Control Template Examples, they discuss the entire structure of it, the borders, backgrounds, glyphs, actions, properties, etc.
If the ONLY thing I want to do with a combobox is to change the border of it to Red if there is an error in it, it appears, I have to basically redefine the entire thing and somehow put in my custom trigger setting / color to be implemented.
Somewhat similar is that of the textbox control and how its created. It has the named control when trying to nuts around with the background color... you can't just say... background = some static brush value.
What shortcuts are out there to only allow overriding these small elements without having to re-create the entire template control. I can just imagine what would go on with grids, tabbed controls, and others that could get extremely messed up if you miss one simple thing.
I also see that some controls are made up of OTHER Control.Templates, so how might I be able to attach to changing the property setting on just the single element of the control template... Such as the combobox has the control template for the Toggle Button. From that, it has a border via x:Name="Border" and I want to change THAT element within a derived style.
Thanks
I might not understand your question here. But from what i get is:
Yes you can't partially implement Templates, in fact i wouldn't know how this could be possible. But, if you want to change certain things, you can of course do that. You can create Styles, Templates, Brushes etc. as DependencyProperties and use TemplateBinding to bind to them, on the given child control.
Remember that WPF allows always to change the template on the fly. if we could partially change the template this would might hurt performance or could get messy and complicated. Still, you can do that using ContentControls and TemplateBinding or simply Triggers.
For my custom controls, which might contain multiple part sub controls, i usually add a style for them. For example, a custom ComboBox would contain a ToggleButtonStyle.
One thing that would be nice though, would be to add control template triggers without the need to reimplement the template.

A window that behaves both modally and non-modally

I want to create a WPF window that behaves as a modal dialogue box while at the same time facilitating selected operations on certain other windows of the same application. An example of this behaviour can be seen in Adobe Photoshop, which offers several dialogues that allow the user to use an eyedropper tool to make selections from an image while disabling virtually all other application features.
I'm guessing that the way forward is to create a non-modal, always-on-top dialogue and programmatically disable those application features that are not applicable to the dialogue. Is there an easy way to achieve this in WPF? Or perhaps there's a design pattern I could adopt.
Yes, there is the traditional approach you describe where you programmatically enable/disable features, but WPF also opens up several new possiblities that were really not possible in WinForms and older technologies.
I will explain four WPF-specific ways to do this:
You can secretly and automatically replace a window's contents with a picture of its contents using a Rectangle with a VisualBrush, thereby effectively disabling it. To the user it will look as if the window is unchanged, but the actual contents will be there underneath the picture, so you can use it for hit-testing and even forward selected events to it.
You can add a MergedDictionary to your window's ResourceDictionary that causes all TextBoxes to become TextBlocks, all Buttons to become disabled, etc, except as explicitly overridden using custom attached properties. So instead of looping through all your UI selectively enabling/disabling, you simply add or remove an object from the MergedDictionaries collection.
You can use the InputManager to programmatically generate and process real mouse events in particular parts of a disabled window, disallowing any mouse events that don't hit-test to something "approved."
Use data binding and styles to enable/disable individual controls rather than iterating through them
Details on replacing window with picture of window
For this solution, iterate your app windows and replace each content with a Grid containing the original Content and a Rectangle, like this:
<Window ...>
<Grid>
<ContentPresenter x:Name="OriginalContent" />
<Rectangle>
<Rectangle.Fill>
<VisualBrush Visual="{Binding ElementName=OriginalContent}" />
</Rectangle.Fill>
</Rectangle>
</Grid>
</Window>
This can be done programmatically or by using a template on the Window, but my preference is to create a custom control and create the above structure using its template. If this is done, you can code your windows as simply this:
<Window ...>
<my:SelectiveDisabler>
<Grid x:Name="LayoutRoot"> ... </Grid> <!-- Original content -->
</my:SelectiveDisabler>
</Window>
By adding mouse event handlers to the Rectangle and calling VisualTreeHelper.HitTest on the ContentPresenter to determine what object was clicked in the original content. From this point you can choose to ignore the mouse event, forward it to the original content for processing, or in the case of an eyedropper control or an object selection feature, simply extract the desired objects/information.
Details on MergedDictionary approach
Obviously you can restyle your whole UI using a ResourceDictionary merged into your window's resources.
A naiive way to do this is to simply create implicit styles in the merged ResourceDictionary to make all TextBoxes appear as TextBlocks, all Buttons appear as Borders, etc. This does not work very well because any TextBox with its own style or ControlTemplate explicitly set may miss the updates. In addition, you may not get all objects as desired, and there is no way to easily remove the Commands or Click events from buttons because they are explicitly specified and the style won't override that.
A better way to work this is to have the styles in the merged ResourceDictionary set an attached property, then use code-behind in the PropertyChangedCallback to update the properties you really want to change. Your attached "ModalMode" property, if set to true, would save all the local values and bindings for a number of properties (Template, Command, Click, IsEnabled, etc) in a private DependencyProperty on the object, then overwrite these with standard values. For example a button's Command property would be set to null temporarily. When the attached "ModalMode" property goes false, all the original local values and bindings are copied back from the temporary storage and the temporary storage is cleared.
This method provides a convenient way to selectively enable/disable portions of your UI by simply adding another attached property "IgnoreModalMode". You can manually set this to True on any UIElements that you don't want the ModalMode changes to apply to. Your ModalMode PropertyChangedCallback then checks this and if is true, it does nothing.
Details on InputManager approach
If you capture the mouse, you can get mouse coordinates no matter where it is moved. Translate these to screen coordinates using CompositionTarget.TransformToDevice(), then use CompositionTarget.TransformFromDevice() on each candidate window. If the mouse coordinates are in bounds, hit-test the disabled window (this can still be done even when a window is disabled), and if you like the object the user clicked on, use InputManager.ProcesInput to cause the mouse event to be processed in the other window exactly as if it was not disabled.
Details on using data binding
You can use a styles to bind the IsEnabled property of Buttons, MenuItems, etc to a static value like this:
<Setter Property="IsEnabled" Value="{Binding NonModal, Source={x:Static local:ModalModeTracker.Instance}}" />
Now by default all items with these styles will automatically disable when your NonModal property goes false. However any individual control can override with IsEnabled="true" to stay enabled even in your modal mode. More complex bindings can be done with MultiBinding and EDF ExpressionBinding to set whatever rules you want.
None of these approaches require iterating through your visual interface, enabling and disabling functionality. Which of these you actually select is a matter of what functionality you actually want to provide during modal mode, and how the rest of your UI is designed.
In any case, WPF makes this much easier than it was in WinForms days. Don't you just love WPF's power?
What you're looking for is similar to a Multiple Document Interface. This isn't available by default in WPF but there are some efforts out there to support this, both free and commercial.
It will be up to you to identify the current state of the application and enable/disable UI elements in response to this.
I think an always-on-top windows that programmatically disables certain app features is the way to do this. It might be easier to keep a "white list" of features that can be enabled while this form is open, and then disable everything that isn't on the list (as opposed to trying to maintain a "black list" of everything that can't be enabled).
I believe the best approach to solve this is using the InputManager approach mentioned previously. This design pattern allows you to connect commands to your toolbar buttons/menu items etc and each will call a CanExecute handler you specify for your command. In this handler, you would set the command to not enable if your always-on-top non-modal window was open.
http://msdn.microsoft.com/en-us/library/ms752308.aspx

Inheriting styles in custom WPF controls

I have a datagrid, and certain columns need to contain text that is linked to a detail window. So, in order to make it a bit easier on myself, I created a UserControl that is basically a Button with a control template that contains a TextBlock (I could have done this a number of other ways, I know, but I figured the button already exposes a Click event, so why not?). Things are getting a bit hairy, though, when it comes to styling: I'd like to give the text a "hyperlink" sort of format--blue text, underlined--so that it's clear they are links (also, so that they resemble to format in the legacy WinForms application I'm re-implementing). But I would also like to be able to style the text--ideally, it should grab things like text color if text color is set in a style on the parent cell.
Basically, is there an easy way to implement a custom UserControl that will a) grab styles from a parent element and b) apply its default styles in a low-priority way, i.e. only apply a specific style if there's not already one set from the parent? I know I can pass the parent's style manually through a binding, but I was wondering if there was an easier way.
It sounds like you need to create a true Control or ContentControl implementation for this, so that you can override the true styles and templates.
UserControls are not really stylable, unless you start somehow creating custom properties for binding Styles.. but none of that will be implicit.

Best way to modify Button behavior and Content, but maintain styles?

I'm trying to create a control in Silverlight that inherits from Button so that I can perform a specific action everytime it is clicked. I'm doing this because I'd like to reuse this custom button in several locations with the same functionality.
I'd like to create the control in such a way so that I have a can set the custom Button's Content to a specific default icon image, but still have the rest of the button's style coming from either the default button style, or being automatically set by the toolkit Themes.
I'd also like to have the Content be described and editable in XAML rather than code if possible.
It seems like this would be a pretty common problem for Silverlight developers - is there a good way to tackle it?
If you use a normal button and edit an "Empty Template", then you can style the button to have any content you wish and expose properties that you can set in the XAML for Icons etc.
By using the standard button control, you will have all the behaviors that you require.
I believe this is what you're looking for, if not can you expand on your question.
--EDIT--
Ok, I get what you are trying to do now. So what you might want to consider is creating a custom button class that inherits from Button. Then you can override the OnClick method to handle your logic. When it comes to the XAML, you can create a template style for a TargetType of your custom button class, that would be styled to your requirements.
HTH, if you need some examples place a comment and I'll mock up some examples

What is the difference between modifying a control by altering the control template and adding sub controls

I am new to WPF and I have a doubt in modifying a control. I came to know that one can modify a control by changing its Control Template. i.e.,
<Button>
<Button.Template>
<ControlTemplate>
...
</ControlTemplate>
</Button.Template>
</Button>
Also we can edit a control utilizing the Content Model. i.e.,
<Button>
<Grid>
<CheckBox>
</CheckBox>
<RadioButton>
</RadioButton>
...
</Grid>
</Button>
What is the difference between these two techniques. Which one is the correct way to customize a control in WPF. Please help me in understanding this better.
The primary difference between these two things, is that the ControlTemplate defines the look of the control. It is not actually placing content inside of it. At some location inside the content control, there should be some form of ContentPresenter. The built in controls are capable of this because they are what is known as 'lookless controls', and any custom controls created should also be lookless. When a control is not templated in a lookless manner but instead has a static layout, then the confusion you have run into can occur.
As for the correct way to do things, it depends on what you are trying to achieve. If you are attempting to change the control, such as the look and feel or the behavior, then using a ControlTemplate, (or DataTemplate, depending on what you are templating), is definitely the way to go. A good example of this is the CheckBox, belive it or not, the CheckBox is actually a ToggleButton (more or less), that through templating displays the togleablity in a bullet. Here's another very good example of how you can use Templates to do some very nifty things.
ControlTemplates should also be applied through Styles, instead of directly set on an element.
If you aren't actually aiming to modify the behavior or look of the control then using the content model is the correct approach.
WPF does this better then Silverlight, though I don't know if there are improvements in SL3.
My rule of thumb is that if it's possible to get what I want without changing the control template then you shouldn't change the control template.
control templates are a way to change the look&feel of a control, for example making a round button of changing the check mark graphics of a checkbox.
adding controls inside a control is simpler, for example place an image inside a button.
Also remember, there is a lot of functionality in the control template, including padding, content alignment, disabled look and more, if you change the control template you will have to add support for all of those features.
Template can be placed into a resource and re-used for another button.
Changing content directly is not re-usable unless you make a UserControl out of it.
Which one you use depends on a concrete task and your personal preferences.

Resources