Reusing a customized style in Silverlight - c#

By modifying the RowStyle of a DataGrid I have created a customized grid that will display some buttons at the end of the row when the mouse hovers above the row:
I created a new style for DataGridRow based on the default style. I then modified the XAML to add my buttons inside a StackPanel (details omitted):
<UserControl.Resources>
<Style x:Key="DataGridRowStyle" TargetType="swcd:DataGridRow">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="swcd:DataGridRow">
...
<StackPanel x:Name="RowControlsPanel">
<Button>
... these are the buttons displayed on the row
The DataGrid is modified using the style:
<swcd:DataGrid RowStyle="{StaticResource DataGridRowStyle}">
...
</swcd:DataGrid>
I want to create another grid in a similar manner, but with a different set of buttons at the end of the row. I could create a textual copy of my style and modify it accordingly, but I was hoping that I could create a proper reusable class. I'm not sure how to approach this since the stuff I want to factor out of my style is a collection of controls (buttons) inside a style.
My approach so far is to create a MyDataGrid class derived from DataGrid. I have added a new property RowControls to MyDataGrid enabling me to instantiate it like this:
<local:MyDataGrid>
<local:MyDataGrid.RowControls>
<Button>
... these controls should go at the end of the row
</local:MyDataGrid.RowControls>
...
</local:MyDataGrid>
MyDataGrid uses a RowStyle as described above. But how do the contents of the MyDataGrid.RowControls collection get into the Content of RowControlsPanel in the style? I think I should do that in OnApplyTemplate of the DataGridRow, but then I need to derive a new MyDataGridRow class from DataGridRow. Unfortunately it seems that DataGrid is hardcoded to use DataGridRow and I'm not able to inject my own derived row class. I get the feeling that I need to approach my problem of reuse in a different manner, but I'm not sure how?
Customizing simple controls like buttons by adding new properties and modifying the control template is quite easy, but how do I customize a complex control like DataGrid where the template I need to customize is nested inside the grid?

Instead of creating a reusable class you might consider reusing your style with a Silverlight 3 BasedOn style:
http://community.irritatedvowel.com/blogs/pete_browns_blog/archive/2009/03/18/Silverlight-3-1320-BasedOn-Styles.aspx
That technique will allow you to make minor modifications, like changing the row buttons in your example, to an existing style.

Related

How to reference the default style ControlTemplate for ListViewItem in WPF?

In WPF, if I apply a GridView to a ListView, then it will automatically change the Template property of the ListViewItem to a ControlTemplate that uses a GridViewRowPresenter instead of a ContentPresenter. This is usually what you want.
As it happens, though, I have a case where I want to keep the original ContentPresenter, so that it will render the ItemTemplate of the ListView.
(For the curious: I'm doing a parent-child thing where the columns are actually for the child elements, so while I do still have a GridViewRowPresenter, it's inside another list control inside the ItemTemplate of the ListView.)
I can do this by setting an ItemContainerStyle on the ListView, and setting the Template property in that to a custom ControlTemplate, since this will override the style setter that the GridView applies.
However this gets really wordy (especially to keep the selection colours) and it breaks the natural theme support, unless I make duplicate copies of the template for each theme, which is definitely silly.
What I really want to do is to write this:
<Setter Property="Template"
Value="{StaticResource {FindDefaultControlTemplate ListViewItem}}" />
Where the latter bypasses the ControlTemplate set by the GridView and obtains the ControlTemplate that a normal ListViewItem would have used.
Alternatively, if there's some way to tell a GridView to not alter the ListViewItem style at all, that would also work for my scenario.
This has to work inside XAML.
It appears that the magic incantation is to set this style:
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem"
BasedOn="{StaticResource {x:Type ListBoxItem}}" />
</ListView.ItemContainerStyle>
Apparently ListViewItem itself doesn't have a default style, but ListBoxItem does.
And this does override whatever GridView does and makes it use a plain ContentPresenter again.

WPF hide slider track

I'm using WPF (and the MVVM framework) to create an interface which has a slider on it.
<Slider Value="{Binding MotorDemandSpeed}" Maximum="3500" />
I'm trying to hide the track part on the slider so that you are left with just the 'thumb tack'. This is what the slider currently looks like (styles are controlled by a theme):
I've looked around at various methods, however I can't find a method that changes only a single slider.
Help is appreciated.
You need to set the Template property of this particular Slider instance to be able to override its ControlTemplate:
<Slider Value="{Binding MotorDemandSpeed}" Maximum="3500">
<Slider.Template>
<ControlTemplate TargetType="Slider">
<!-- define the custom template without a track here... -->
</ControlTemplate>
</Slider.Template>
</Slider>
In order to change the appearance of a control you will need to modify the control template. Each control is made up of many parts, and each part many objects. You can modify individual parts (such as the track) with the correct x:Key and TargetType.
This Question has an example of modifying a scrollbar control template, which is most likely similar to the template of this slider you have. The first step would be to identify the Xaml file in your theme which this slider uses and find the parts that define the trackbar, thumb, etc. From there you should be able to recreate the control to your liking, or just completely remove parts you do not need.
Are you using any third party controls that may have information on how to edit their themes? Perhaps try investigating Modifying Control Templates to get a better understanding of control templates.
Here is the MDSN page for the slider control template, you may find this useful.

customize Style CheckList RadTreeView

Is there a way to change the style of checkboxes when the ItemsOptionListType="CheckList"
inside a RadTreeView?
There are a couple of ways of doing this that I can think of, but sadly neither of them is particularly easy.
One way is to use Blend or a similar tool to obtain the template for the RadTreeViewItem class. The RadTreeViewItem class and its template are in the Telerik.Windows.Controls.Navigation assembly. Take a copy of this template and modify the CheckBox within this template to customise its appearance as you wish.
To use the template, add a ControlTemplate and a Style to the <UserControl.Resources> element of a XAML page, as follows:
<UserControl.Resources>
<ControlTemplate x:Key="myRadTreeViewItemTemplate" TargetType="telerik:RadTreeViewItem">
<!-- modified template goes here... -->
</ControlTemplate>
<Style TargetType="telerik:RadTreeViewItem">
<Setter Property="Template" Value={StaticResource myRadTreeViewItemTemplate}" />
</Style>
</UserControl.Resources>
This should then apply the modified template to any RadTreeViews in the same XAML file.
Note that we have to use an implicit style (i.e. one without an x:Key), since there seems to be no other way to tell a RadTreeView to apply a given style to its child items.
Alternatively, you can modify a built-in theme. This approach could also change the styles of CheckBoxes used within other Telerik controls in your application, for example in a GridViewCheckBoxColumn within a RadGridView.
EDIT: if you want the template for the CheckBox as used in the RadTreeView by default,
you'll find it in Themes\Office\Black\System.Windows.Controls.xaml within the Telerik.Windows.Controls assembly. This assumes you're using the 'Office Black' theme; adjust the path of this file if you're using a different Telerik theme.

Difference between Style and ControlTemplate

Could you tell me what is the main differences between Style and ControlTemplate ?
When or why to use one or the other ?
To my eyes, they are exactly the very same. As I am beginner I think that I am wrong, thus my question.
In a style you set properties of a control.
<Style x:Key="MyButtonStyle" TargetType="Button">
<Setter Property="Background" Value="Red"/>
</Style>
<Button Style="{StaticResource MyButtonStyle}"/>
All buttons that use this style will have their Backgrounds set to Red.
In a template you define the UI (structure) of the control.
<ControlTemplate x:Key="MyButtonTemplate" TargetType="Button">
<Grid>
<Rectangle Fill="Green"/>
<ContentPresenter/>
</Grid>
</ControlTemplate>
<Button Template="{StaticResource MyButtonTemplate}"/>
All buttons that use this template will have a green background that cannot be changed.
Values set in a template can only be replaced by replacing the entire template. Values in a style can be replaced by setting the value explicitly when using the control. That is why is better to use the properties of the control by using TemplateBinding instead of coding values.
<ControlTemplate x:Key="MyButtonTemplate" TargetType="Button">
<Grid>
<Rectangle Fill="{TemplateBinding Background}"/>
<ContentPresenter/>
</Grid>
</ControlTemplate>
Now the template uses the value of the Background property of the button it is applied to, so it can be customized:
<Button Template="{StaticResource MyButtonTemplate}" Background="Yellow"/>
Another useful feature is that controls can pick up a default style without having a specific style being assigned to them. You can't do that with a template.
Just remove the x:Key attribute of the style (again: you can't do this with templates). All buttons in the visual tree below the style will have this style applied.
Combining Templates and Styles is extra powerful: you can set the Template property in the style:
<Style TargetType="Button">
<Setter Property="Background" Value="Red"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<Rectangle Fill="{TemplateBinding Background}"/>
<ContentPresenter/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
No indeed you are quite wrong.
Styles set properties on controls. ControlTemplate is a property shared by most controls that specify how they are rendered.
To elaborate, you can use a style to group settings for a bunch of properties so you can re-use that to standardize your controls. Styles can be set explicitly on controls or applied too all of a certain type.
Control Templates can be set by a style or set explicitly on a control to change the way it appears. All controls have default templates (and styles for that matter) that are embedded in the .net wpf assemblies. It is quite enlightening to see these and understand how the wpf developers implemented the normal versions of all controls. If you have Expression blend installed, look in its "SystemThemes" folder.
UPDATE:
To understand how Styles and ControlTemplates can "add controls". In some way or another, the ControlTemplate is the only way to define the controls a control is made up of. But, some default .net controls allow you to use controls in place of text.
For example:
<GroupBox>
<GroupBox.Header>
<CheckBox/>
</GroupBox.Header>
</GroupBox>
This "adds" a checkbox to the groupbox without changing the ControlTemplate, but this is because the default ControlTemplate for GroupBox allows anything as the Header. This is done by using special controls such as ContentPresenter.
However, sometimes the default ControlTemplate for a control doesn't allow you to change something that you want to change via properties. Then you must change the ControlTemplate.
Whether you set the Properties of a control (Content, Header, ControlTemplate, IsEnabled, etc.) directly or via a style does not matter, Styles are only a convenience.
Hopefully this answers your question more clearly.
You can think of a Style as a convenient way to apply a set of property values to more than one element. You can change the default appearance by setting properties, such as FontSize and FontFamily, on each TextBlock element directly. However, if you want your TextBlock elements to share some properties, you can create a Style in the Resources section of your XAML file.
On the other hand, a ControlTemplate specifies the visual structure and visual behavior of a control. You can customize the appearance of a control by giving it a new ControlTemplate. When you create a ControlTemplate, you replace the appearance of an existing control without changing its functionality. For example, you can make the buttons in your application round instead of the default square shape, but the button will still raise the Click event.
Ref: http://msdn.microsoft.com/en-us/library/ms745683.aspx
I found some interesting differences in
The difference between styles and templates (msdn)
Style:
You can set only pre-existing properties in the style. For example, you cannot set a default value for a property that belongs to a new part that you added to the template.
Template:
When you modify a template, you have access to more parts of a control than when you modify a style. For example, you can change the way the pop-up list appears in a combo box, or you change the look of the button that triggers the pop-up list in the combo box by modifying the items template.
Style:
You can use styles to specify the default behavior of a control. For example, in a style for a button, you can specify a trigger so that when users move their mouse pointer over the button, the background color will change. These property changes are instantaneous (they cannot be animated gradually).
Template:
You can specify the behavior of any new and existing parts in a template by using triggers. For example, you can specify a trigger so that when users move their mouse pointer over a button, the color of one of the parts will change. These property changes can be instantaneous or animated gradually to produce a smooth transition.
OK, I had the exact same question and the answers I found in this thread pointed me in the right direction so I'm sharing, if only so I can understand it better myself.
A Style is more flexible than a ControlTemplate.
From Windows Presentation Foundation Unleashed, Adam Nathan and gang (writers) state this:
"Besides the convenience of combining a template [with a style using the Style's ControlTemplate setter] with arbitrary property settings, there are important advantages of doing this [setting the ControlTemplate setter on a style]:
It gives you the effect of default templates. For example, when a typed Style gets applied to elements by default, and that Style contains a custom control template, the control template gets applied without any explicitly markings on those elements.
It enables you to provide default yet overridable property valus that control the look of the template. In other words, it enables you to respect the templated parent's properties but still provide your own default values."
In other words, creating a style allows the user of the Style's Template setter to override the values set, even if they did not use a TemplateBinding ({TemplateBinding Width} for example). If you hardcoded the Width in your style, the user of the Style could still override it, but if you hardcoded that Width property in a Template, the user is stuck with it.
Also, (and this is kind of confusing) when using a ContentTemplate with a TemplateBinding the onus is on the user to set that property otherwise it will use the default property for the TargetType. If you use a style, you can override the default property of the TargetType by using a setter for the property and then applying a TemplateBinding referencing back to that setter. The book explains it better, page 338 (Mixing Templates with Styles)

How to subclass a WPF ComboBox to add an extra button

I saw a similar question and hoped for a solution, but simply giving an advice to subclass the ComboBox is not enough for me. I need it in small spoons...
The case is I need an extra button on my special comboBox for adding new records to the item list. I have this as an UserControl today but it doesn't look good and I need more controls on my views, so I started making a custom control trying to extend ComboBox.
I didn't get far... Please lend me a hand... :)
My code so far:
public class ComboBoxWithAdd : ComboBox
{
static ComboBoxWithAdd()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ComboBoxWithAdd), new FrameworkPropertyMetadata(typeof(ComboBoxWithAdd)));
}
}
In Generic.xaml I have this:
<Style TargetType="{x:Type local:ComboBoxWithAdd}" BasedOn="{StaticResource {x:Type ComboBox}}">
</Style>
When making the decision to create a custom control you need to determine whether you need to add actual behavior or just UI. Just adding a button can be done by just customizing the ControlTemplate. It sounds like you want a button that causes an action that will update the Items of the ComboBox which would point to the direction you started down of deriving a control from ComboBox. You'll need to add a few things on the code and XAML side. In your Style you'll need to add a Setter for the ControlTemplate and start with a copy of the default template for ComboBox (I usually do this with Blend but there are other sources out there). You can then add in your new Button wherever you want it in the template.
<Style TargetType="{x:Type local:ComboBoxWithAdd}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:ComboBoxWithAdd}">
... copy of default template with your modifications
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
There are a few different ways you could connect the button but the most robust is to use a command that you can bind to in your control code. You can declare your own RoutedCommand in your control code later but to get started just use a built in one.
public ComboBoxWithAdd()
{
CommandBindings.Add(new CommandBinding(ApplicationCommands.New, NewExecutedMethod));
}
Then in the NewExecutedMethod just add whatever logic you want to do the actual action to add an item (probably working with the ComboBox's Items/ItemsSource). To connect the button up just set Command="ApplicationCommands.New". There's a lot more that can be done with a custom control but this should get you started.
Rozon, You can manipulate the Combobox from the code behind like this without creating a complex template:
public class CustomComboBox : ComboBox
{
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
Grid grid = WpfHelper.FindAllChildrenByName<Grid>(this, "MainGrid").SingleOrDefault() as Grid;
if (grid != null)
{
grid.ColumnDefinitions.Add(new ColumnDefinition());
Button button = new Button();
button.Content = "test";
button.SetValue(Grid.ColumnProperty, 2);
grid.Children.Add(button);
}
}
}
WpfHelper is just a class which finds a visual child by its name. Notice that this might break easily if the standard control template of the combobox is changed and MainGrid is renamed.
I would suggest you to use the UserControl that you created by adding one more button and grouped them to make a user control and exposing the required events and commands.
Custom control is not advisable.
But, if you have requirement like that. Here we go:
1) You need to derive the control for what you are trying to extend the capability.
2) You need to create a default Template for the control. [Generic.Xaml]
Rest is your customization.
But, one advantage is you could get a easily Skinnable control.
HTH

Categories

Resources