Overriding method of an element within a XAML UserControl? - silverlight

I have a Silverlight user control that has no template and does not need one as it is simply a path with a RectangleGeometry that is resized by code. Now our designed has added a template to the tooltip of the path and I want to be able to provide a method for users of the control to change the layout of a portion of this template. If the template was part of an overall one for the control I could simply override the control's OnApplyTemplate method and grab a reference to the section I want to modify. But as the control has no template the overridden method in the control's code-behind is never called.
Is there some way I can override the OnApplyTemplate method for the templated element in the control's code behind?

What is the base-class. You can't override OnApplyTemplate if the underlying class doesn't support templates. I think you'd be best to just change the tooltip style when the value is set (as its unlikely to show up anyway).
Any reason you can't just do GetTemplateChild as the path changes? That should be late enough in the lifetime.

Related

How is a a ControlTemplate instantiated in XAML?

In code a ControlTemplate contains a hierarchy of FrameworkElementFactory that can be used to construct the framework elements themselves. But, in XAML, a ControlTemplate's content appears as the elements themselves.
Does the XAML parser convert from one object form to the other, is a ValueConverter used, or does it actually create the factories as it parses the ControlTemplate content?
It is actually done differently, if it's defined in XAML versus in code. To verify, you can create a simple project in WPF with a single Window and add a custom Control that has a ControlTemplate defined in XAML by it's default Style. Then add the control to your window and add a Button, whose Click handler includes a breakpoint.
When the breakpoint is hit, we can inspect the custom control and it's ControlTemplate. The VisualTree property (which is FrameworkElementFactory) is null.
Using Reflector, we can see the relevant code in the StyleHelper.ApplyTemplateContent method. The first if-statement in that method, applies a FrameworkElementFactory (which is passed in from the VisualTreeProperty). The second if-statement loads the ControlTemplate from XAML, which ultimately executes FrameworkTEmplate.LoadOptimizedTemplateContent.

Templates in extended Silverlight controls

i am looking to extend a third party control, it is a ComboBox (so it isn't the standard Silverlight one, but that shouldn't matter for this question). To do this, i add a new template control to my controls project, then i change the new control to inherit from ComboBox instead of Control. A style has been created for me in the generic.xaml file, so i delete the default border stuff that was inserted, and then add a property setter for the PopupTemplate.
My problem is that when doing it this way, the combobox doesn't (visibly) render in the silverlight application anymore. However, in the constructor of my extension if i comment out the line
this.DefaultStyleKey = typeof(MyComboBox);
and put the PopupTemplate xaml bit in the main silverlight page, it renders correctly. I want the popup template to be declared within the control library, but does this mean that i also have to define the regular Template property? Am i wrong in thinking that anything i don't explicitly specify should just be inherited from the base control?
A control can only have one default style. You need to copy the entire default style of the base control into the Generic.Xaml for you new MyComboBox then adjust it accordingly.

What are your 'best practices' for writing custom controls in WPF

I have started writing some custom controls for a highly visual project. I was wondering what are your 'best practices' when coding WPF custom controls?
If you want your custom control to support direct content like this:
<CustomObject>
Direct content example 1
</CustomObject>
<!-- or -->
<CustomObject>
<Button Content="Direct content example 2" />
</CustomObject>
Then you need to use the ContentPropertyAttribute which tells WPF which property is actually being set when you write xaml like this.
The attribute can be used like this:
[ContentProperty("NameOfProperty")]
public class CustomObject
{
[...]
ContentControl uses this attribute to set the Content property but note that the property can be called anything; the WPF TextBox, for example uses this attribute to set the Text property.
E.G.
[ContentProperty("Text")]
The property also does not have to be a dependency property (see the MSDN documentation example for evidence of this).
Finally, this attribute is specific to the xaml parser and not to ContentControl and can be used with any type which can be seen from the TextBox example above (TextBox does not derive from ContentControl).
Keep property names the same as the property names for built-in Controls if you can do so without changing their meaning.
e.g. if you have a CustomerDisplayer custom control don't call the list of customers Customers, call it ItemsSource.
It might seem counter intuitive at first but it saves a lot of headache in the long run because future programmers can make a lot of assumptions about how a property called ItemsSource will act that they can't necessarily make about a Customers property.
Make sure the control can be re-styled and re-templated without changing the way the control operates. Don't make the control assume that the Listbox and Button are both within the same panel or that there even is a Listbox or Button. Check out the MSDN article on control authoring for some recommendations on how to do this.
Some content controls are dependant on the existence of other controls in their ControlTemplate. Typically this should be documented using the TemplatePart attribute.
The Combobox control, for example, is dependant on the existence of a TextBox and a Popup controls in its template.
This would be documented by placing the attribute on the class like so:
[TemplatePart(name="PART_EditableTextBox", type=typeof(TextBox))]
[TemplatePart(name="PART_Popup", type=typeof(Popup))]
public class Combobox : Selector
{
[...]
The naming convention is "PART_controlIdentifier".
The relevant items would then be given the same names in the control template so that they can be located in the OnApplyTemplate method.
This then allows the control to hook up to events, set properties and call methods on the controls contained in the template.
This attribute is for documentation purposes so that people designing custom control templates (and tools such as Expression Blend) know that the control is dependant on the existence of another.
Learn how to use both dependency properties and routed events (and how they work) so that you can use them effectively in your own control.
Both of these types provide services for integrating your control with the systems built into WPF.
By using these two features in your custom controls you will get the following advantages:
Dependency Properties provide support for databinding, animations and can be used in styles.
Routed Events can be propogated through the visual tree which means that other elements can handle the events.

Is there a workaround for the missing FindName method in Silverlight's DataTemplate?

According to the C# compiler and the Silverlight 2 documentation, Silverlight doesn't provide a FindName method for the DataTemplate class. I want to find a Border that's inside a ContentPresenter. What's the best way in SilverLight 2?
If the border is inside a DataTemplate, not a ControlTemplate, then the only way I've been able to do that in the past is to use VisualTreeHelper to locate the element I need.
Not totally sure I understand the scenario, but since you mention the DataTemplate I'm assuming you're using a template.
If you're using a template then what you do is give your border a name (x:Name="border") and then override the OnApplyTemplate method. In that method you use GetTemplateChild and pass the name you used. This will return a reference to your border.
If you're not use a template and have a reference to the ContentPresenter then you could write a recursive function that looks at the Content property of the child and if it isn't a border then calls your same function on its content.

Silverlight databinding a textBlock in another user control

I have a small usercontrol that basically increments or decrements a value by one. The user control has two buttons(one to add and the other to subtract) and a textBlock that is used to display the value.
I am going to have multiple instance of this usercontrol in another usercontrol so I can manipulate values of a dataclass that has an INotifyPropertyChanged interface. My question is how can I databind the textBlock of the value changing usercontrol to the usercontrol I instansiated it in?
First, I want to state that Silverlight 2 does not support element to element binding. That feature is added in Silverlight 3 (out in Beta now). Having said that, I don't think you want to bind controls together anyway. It sounds like you're trying to build a NumericUpDown control and you probably have some class in code behind that's actually doing the incrementing and decrementing.
If that's the case, you can simply subscribe to the click handlers and call a method on your model like Increment or Decrement. Your model can expose a property for the current value and that property is what is bound to your text box.
Now if you're actually trying to build a NumericUpDown control, you might want to check out the Silverlight Toolkit. The toolkit already includes this control and it also supports data binding.
Check out the NumericUpDown Control here and download the toolkit here.
Finally, binding from a child control to a parent control really isn't any different. The parent UserControl has a DataContext and all child controls inherit that. Each individual child control can also have its DataContext set. Binding expressions are always relative to the DataContext and the DataContext can be set in code. In your case, probably to a model of some sort.
I hope that helps.

Resources