Reputation: 918
I have a WPF control ParentWPFControl from a third party that I would like to inherit from (let's call the child class ChildWPFControl). In the process, I plan to override some of the back-end logic and parts of the front end styles. I can do the former just fine but I have problems doing the latter.
I attempt to use a xaml <-> xaml.cs structure for the child country, but that appears to be not allowed with the following warning from VS:
Partial declarations of 'ChildWPFControl' must not specify different base classes
Now, I suppose I can write a ResourceDictionary XAML and define the front end there, but that becomes a problem if I want to add event handlers to the XAML (at least I couldn't find a way to do that)
Another alternative I have is to define the override template directly in the objects that use the ChildWPFControl but that makes the design less modular.
A final alternative I can think of is to make a xaml <-> xaml.cs pair that is a XAML style container and then force the ChildWPFControl to use the ControlTemplate defined within through the back end event handler.
Anyway, what I am looking for is an elegant and modular solution for my problem. Any advice would be welcomed.
Thanks
Upvotes: 2
Views: 10020
Reputation: 16142
It looks like you have your inheritance mixed up more than that it is not allowed. Your root element of your xaml must match the base class of your xaml.cs.
If you are defining the base class in the same project, you will not be able to use it as the base class in the xaml, because it itself is still xaml and not a compiled control yet. Some ways to solve this: You can compile it in a seperate project and reference it, you can compile the base class entirely in .cs instead of a partial class, or you can use some style wizardry. Here is a link with examples of the last two: http://svetoslavsavov.blogspot.ca/2009/09/user-control-inheritance-in-wpf.html
Upvotes: -2
Reputation: 3261
You can create your user control as wrapper, containing base control. In this way you can change styles in xaml add some logic in C# for wrapped contrоl. But it's tediously process.
Edit:adding sample(wrapper for telerik:RadComboBox )
XAML:
<UserControl x:Class="Controls.SingleDictionaryValueSelector"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:CardControls="clr-namespace:Controls"
xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation" MinWidth="150" MinHeight="25" >
<Grid >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="25"></ColumnDefinition>
</Grid.ColumnDefinitions>
<!-- customize visual for wrapped control -->
<telerik:RadComboBox x:Name="cb"
Grid.Column="0"
VerticalAlignment="Center"
SelectedValuePath="Key"
ClearSelectionButtonContent="Clear"
ClearSelectionButtonVisibility="Visible"
CanAutocompleteSelectItems="True"
CanKeyboardNavigationSelectItems="True"
SelectAllTextEvent="None"
OpenDropDownOnFocus="false"
IsFilteringEnabled="True"
TextSearchMode="Contains"
EmptyText="Select item"
telerik:StyleManager.Theme="Metro"
FontFamily="Calibri"
FontSize="14"
IsEditable="True"
Foreground="#666"
KeyDown="cb_KeyDown"
SelectionChanged="cb_SelectionChanged"
GotMouseCapture="cb_GotMouseCapture"
DropDownOpened="cb_DropDownOpened"
KeyUp="cb_KeyUp">
<telerik:RadComboBox.ItemTemplate>
<DataTemplate>
<TextBlock TextWrapping="Wrap" Width="{Binding RelativeSource={RelativeSource AncestorType=telerik:RadComboBox},Path=ActualWidth}" Text="{Binding Path=Value}" />
</DataTemplate>
</telerik:RadComboBox.ItemTemplate>
</telerik:RadComboBox>
<CardControls:ErrorInfo x:Name="errorInfoControl" Grid.Column="1" Visibility="Hidden"></CardControls:ErrorInfo>
</Grid>
</UserControl>
CS:
public partial class SingleDictionaryValueSelector : IMyCustomInterface
{
....
private void cb_KeyDown(object sender, KeyEventArgs e)
{
RadComboBox senderCombo = sender as RadComboBox;
...
}
private void cb_KeyUp(object sender, KeyEventArgs e)
{
SearchExecute();
}
private void cb_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
RadComboBox senderCombo = sender as RadComboBox;
...
}
private void cb_DropDownOpened(object sender, EventArgs e)
{
...
}
...
}
Upvotes: 2
Reputation: 11051
There are a couple of steps necessary to completely override a WPF Control. Some are necessary some are optional depending on your needs. I will explain the two important ones for you:
Creating a new default style
Every WPF control has somewhere a default style which contains it visual representation and override properties. Now if you derive from control WPF still thinks you want to use this default style, to change that you change the DefaultStyle in a static constructor like this
class MyButton : Button
{
static MyButton()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyButton), new FrameworkPropertyMetadata(typeof(MyButton)));
}
}
Now if you use MyButton WPF tries to find a Style for MyButton, not for Button. OverridesDefaultStyle is a property in a style which might also be handy at some points. Usually these default styles should be placed in a theme related xaml.
Event Handlers when overriding classes
It is correct in a ControlTemplate
or Style
you can't use the syntactic sugar of using event like Click="OnClick"
. The point is, that the visual representation is decoupled from the logic part as much as possible. There are other ways though to overcome this, using the OnApplyTemplate method. By overriding this you ask the template "Give me this control" and then you just add your events there.
override OnApplyTemplate()
{
var innerChild = Template.FindName("PART_InnerChild", this) as MyInnerControl;
if(innerChild != null)
innerChild.SomeEvent += OnSomeEvent;
}
Note: The name of these controls usually begin with a PART_ by convention, this can be seen in WPF basic controls aswell. Its a nice way to tell the designers "Without this control, the logic part might break". There is also the attribute TemplatePart but it is not really important, WPF doesn't care about it. AFAIK Expression blend does some with it, personally i use it to tell other people what kind of inner controls are absolutely necessary to make this control work.
Personal advice
Deriving from a class is usually the last step we do when trying to customize controls. Because a lot of work is necessary to fully make it work and it can be limiting in reusability, we try to avoid it, for example a good alternatives are besides template overriding and styling; attached behaviors.
Lastly, The whole subject is covered in a nice MSDN article.
Hope that helps
Upvotes: 7