Using WPF, I want to apply a converter within the binding of the Text property within all my TextBoxes.
The following works for a single TextBox:
<TextBox Style="{StaticResource TextBoxStyleBase2}"
Text="{Binding Text, Converter={StaticResource MyConverter}}">
</TextBox>
However, our TextBoxes uses a style with a Control Template that looks like this:
<Grid>
<Border x:Name="Border"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{StaticResource DefaultCornerRadius}">
<Grid>
<Border BorderThickness="1">
<ScrollViewer x:Name="PART_ContentHost" Margin="0"/>
</Border>
</Grid>
</Border>
</Grid>
How can I apply my converter using this Template?
Thanks!
Any attempt to modify TextBox properties from inside the ControlTemplate will be messy, so I recommend you do it in the Style instead of the ControlTemplate if at all possible. I'll start by explaining how to do it with a Style then explain how to adapt the technique for use in a ControlTemplate if necessary.
What you need to do is create an attached property that can be used like this:
<Style x:Name="TextBoxStyleBase2" TargetType="TextBox">
<Setter Property="local:ConverterInstaller.TextPropetyConverter"
Value="{StaticResource MyConverter}" />
...
</Style>
The ConverterInstaller class has a simple attached property that installs the converter into any Binding initially set on the TextBox:
public class ConverterInstaller : DependencyObject
{
public static IValueConverter GetTextPropertyConverter(DependencyObject obj) { return (IValueConverter)obj.GetValue(TextPropertyConverterProperty); }
public static void SetTextPropertyConverter(DependencyObject obj, IValueConverter value) { obj.SetValue(TextPropertyConverterProperty, value); }
public static readonly DependencyProperty TextPropertyConverterProperty = DependencyProperty.RegisterAttached("TextPropertyConverter", typeof(IValueConverter), typeof(Converter), new PropertyMetadata
{
PropertyChangedCallback = (obj, e) =>
{
var box = (TextBox)obj;
box.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
{
var binding = BindingOperations.GetBinding(box, TextBox.TextProperty);
if(binding==null) return;
var newBinding = new Binding
{
Converter = GetTextPropertyConverter(box),
Path = binding.Path,
Mode = binding.Mode,
StringFormat = binding.StringFormat,
}
if(binding.Source!=null) newBinding.Source = binding.Source;
if(binding.RelativeSource!=null) newBinding.RelativeSource = binding.RelativeSource;
if(binding.ElementName!=null) newBinding.ElementName = binding.ElementName;
BindingOperations.SetBinding(box, TextBox.TextProperty, newBinding);
}));
}
});
}
The only complexity here is:
The use of Dispatcher.BeginInvoke to ensure the binding update happens after the XAML finishes loading and all styles are applied, and
The need to copy Binding properties into a new Binding to change the Converter, since the original Binding is sealed
To attach this property to an element inside the ControlTemplate instead of doing it in the style, the same code is used except the original object passed into the PropertyChangedCallback is cast var element = (FrameworkElement)obj; and inside the Dispatcher.BeginInvoke action the actual TextBox is found with var box = (TextBox)element.TemplatedParent;
Related
I have a Custom window which has two Buttons. One button is named OKButton and the other is named Cancel Button.
<Style TargetType="{x:Type WindowCustom}">
"Properties Here"
<Setter.Value>
<ControlTemplate TargetType="{x:Type WindowCustom}">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
<Button x:Name="OKButton" Content="OK"/>
<Button x:Name="CancelButton" Content="Cancel"/>
"Closing Tags"
I have made a Template part with CLR Properties that for the "OKButton" that gets instantiated in the OnApplyTemplate method.
private const string OKButtonPart = "PART_OKButton";
private Button oKButton;
public Button OKButton
{
get { return oKButton; }
set
{
if (oKButton != null)
{
oKButton.Click += OKButtonClick;
oKButton.Loaded += OKButtonLoaded;
}
oKButton = value;
}
}
public override void OnApplyTemplate()
{
OKButton = GetTemplateChild(OKButtonPart) as Button;
}
Assume all other necessary code to make a custom window is there. I wrote several routed commands to make my OKButton do what I want. This is not ideal because my previous implementation of the button used an ActionMessage (Caliburns way of saying Command)
<Button>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<cal:ActionMessage MethodName="SaveHistoryEntry" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
How do I access my control via XAML to add it to the action message?
What I can do is write the name of my button control on the custom window.
<lc:WindowCustom OKButton="">
I do not know what to do from here.
You could add a dependency property to your WindowCustom class:
public static readonly DependencyProperty OkCommandProperty =
DependencyProperty.Register("OkCommand", typeof(ICommand),
typeof(CustomWindow), new FrameworkPropertyMetadata(null));
public ICommand OkCommand
{
get { return (ICommand)GetValue(OkCommandProperty); }
set { SetValue(OkCommandProperty, value); }
}
...and bind the Command property of the Button in the ControlTemplate to this one:
<Button x:Name="OKButton" Content="OK" Command="{Binding OkCommand, RelativeSource={RelativeSource TemplatedParent}}"/>
You could then set or bind the dependency property of the window to any ICommand source property as usual:
<lc:WindowCustom OkCommand="{Binding YourViewModelCommandProperty}">
The command will be invoked when the Button is clicked. You can of course do the same thing for the cancel Button. Just add another dependency property.
This answer is targeted at Caliburn Users that want to use the ActionMessage functionality on their custom controls.
The button that lies on my custom window looks like this
<lc:ButtonCustom x:Name="PART_OKButton">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<cal:ActionMessage MethodName="{Binding OkCommand, RelativeSource={RelativeSource TemplatedParent}}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</lc:ButtonCustom>
The C# Code on the CustomWindow is almost Identical to the Answer from mm8.
public string OkCommand
{
get { return (string)GetValue(OkCommandProperty); }
set { SetValue(OkCommandProperty, value); }
}
public static readonly DependencyProperty OkCommandProperty = DependencyProperty.Register("OkCommand", typeof(string), typeof(WindowCustom),
new FrameworkPropertyMetadata(null));
I changed the ICommand to a String Datatype, since the ActionMessage accepts a string.
Finally on the window I assign the Action I want to the action message.
<lc:WindowCustom <!--xmlns tags and other dependency proerties-->
OkCommand="SaveHistoryEntry">
It Works!
The question:
Is there a way to define a DataTemplate in XAML and instantiate it in code (rather than retrieve singleton by FindResource) and modify its VisualTree before sending to where a DataTemplate is required such as DataGridTemplateColumn.CellTemplate?
Background:
I am displaying a 2-dimensional array data[][] in a DataGrid by adding DataGridTemplateColumn columns on my own and there is a DataTemplate defined in XAML that knows how to present each element in the array. However the default DataContext for each cell is the row, i.e. data[x]. So I need to "parameterize" the DataTemplate for each column by setting the root visual element's DataContext to binding "[y]" where y is the column index. Currently the DataTemplate is defined as in DataGrid.Resources and retrieved by FindResource() which is returning the same instance every time. Besides calling LoadContent() gives me the UIElement tree rather than loading the VisualTree on the DataTemplate itself. I am looking for a way to instantiate the DataTemplate in code, do the desired modification and set to DataGridTemplateColumn.CellTemplate.
Inspired by Sisyphe's answer, I found this more portable solution:
public class DataGridBoundTemplateColumn : DataGridTemplateColumn
{
public string BindingPath { get; set; }
protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem)
{
var element = base.GenerateEditingElement(cell, dataItem);
element.SetBinding(ContentPresenter.ContentProperty, new Binding(this.BindingPath));
return element;
}
protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
{
var element = base.GenerateElement(cell, dataItem);
element.SetBinding(ContentPresenter.ContentProperty, new Binding(this.BindingPath));
return element;
}
}
Usage:
var cellTemplate = (DataTemplate)this.dataGrid.FindResource("cellTemplate");
foreach (var c in data.Columns)
{
var col = new DataGridBoundTemplateColumn
{
Header = c.HeaderText,
CellTemplate = cellTemplate,
BindingPath = string.Format("[{0}]", c.Index)
};
this.dataGrid.Columns.Add(col);
}
Hope this helps someone who has the same requirement as the one in my question.
(templateKey as DataTemplate).LoadContent()
Description:
When you call LoadContent, the UIElement objects in the DataTemplate are created, and you can add them to the visual tree of another UIElement.
You should see DataTemplate in WPF as a Factory. Thus I think that you don't really need a new instance of the DataTemplate, you just want it to be applied differently based on your context.
If I understand correctly your issue, the problem is that the DataContext of your DataGrid Cells is not correct : it's the Row ViewModel whereas you want it to be the Cell ViewModel (which makes perfect sense). This is however the basic behavior of the DataGrid and is probably tied to the fact that Cells in each rows are hold by a DataGridCellsPresenter (which is basically an ItemsControl) whose ItemsSource dependency property has not been set (thus explaining the bad DataContext).
I've run into this problem and found two way to fix this (but I only managed to make one work).
First one is to subclass DataGridCellsPresenter and override OnItemChanged method to set the ItemsSource manually.
protected override void OnItemChanged(object oldItem, object newItem)
{
var rowViewModel = newItem as ViewModel;
if (rowViewModel != null)
{
ItemsSource = rowViewModel.Items;
}
else
{
ItemsSource = null;
}
}
where rowViewModel.Items should point to something like data[x] in your case. However I ran into some troubles using this fix and couldnt make it work correctly.
Second solution is to subclass DataGridCell and update the dataContext on change of the ColumnProperty. You also have to subclass DataGridCellsPresenter to make it create the right cell controls
public class MyDataGridCell : DataGridCell
{
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
if (e.Property == ColumnProperty)
{
var viewModel = DataContext as YourViewModelType;
if (viewModel != null)
{
var column = (e.NewValue as DataGridTemplateColumn);
if (column != null)
{
var cellViewModel = viewModel[column.DisplayIndex];
DataContext = cellViewModel;
}
}
}
base.OnPropertyChanged(e);
}
}
public class MyDataGridCellsPresenterControl : DataGridCellsPresenter
{
protected override System.Windows.DependencyObject GetContainerForItemOverride()
{
return new MyDataGridCell();
}
}
Finally you will also have to override the DataGridRow default ControlTemplate to make it use your custom DataGridCellsPresenter in place of the original DataGridCellsPresenter.
<ControlTemplate x:Key="DataGridRowControlTemplate" TargetType="{x:Type DataGridRow}">
<Border x:Name="DGR_Border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<SelectiveScrollingGrid>
<SelectiveScrollingGrid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</SelectiveScrollingGrid.ColumnDefinitions>
<SelectiveScrollingGrid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</SelectiveScrollingGrid.RowDefinitions>
<local:MyDataGridCellsPresenter Grid.Column="1" ItemsPanel="{TemplateBinding ItemsPanel}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
<DataGridDetailsPresenter Grid.Column="1" Grid.Row="1" Visibility="{TemplateBinding DetailsVisibility}">
<SelectiveScrollingGrid.SelectiveScrollingOrientation>
<Binding Path="AreRowDetailsFrozen" RelativeSource="{RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type DataGrid}}">
<Binding.ConverterParameter>
<SelectiveScrollingOrientation>Vertical</SelectiveScrollingOrientation>
</Binding.ConverterParameter>
</Binding>
</SelectiveScrollingGrid.SelectiveScrollingOrientation>
</DataGridDetailsPresenter>
<DataGridRowHeader Grid.RowSpan="2" SelectiveScrollingGrid.SelectiveScrollingOrientation="Vertical">
<DataGridRowHeader.Visibility>
<Binding Path="HeadersVisibility" RelativeSource="{RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type DataGrid}}">
<Binding.ConverterParameter>
<DataGridHeadersVisibility>Row</DataGridHeadersVisibility>
</Binding.ConverterParameter>
</Binding>
</DataGridRowHeader.Visibility>
</DataGridRowHeader>
</SelectiveScrollingGrid>
</Border>
</ControlTemplate>
Control template:
<ControlTemplate x:Key="BasicShape2">
<StackPanel Name="sp">
<Border Name="bd" CornerRadius="3.5" BorderThickness="1" BorderBrush="{Binding RelativeSource={RelativeSource TemplatedParent},Path=DataContext.NodeType, Converter={StaticResource NodeTypeColorConverter}, Mode=OneWay}" Height="32" Padding="1">
<TextBlock Name="tbName" Grid.Column="1" Text="" HorizontalAlignment="Center" VerticalAlignment="Bottom" FontSize="16" />
</Border>
</StackPanel>
</ControlTemplate>
a class which this template will apply to:
public class MyThumbEx : Thumb
{
public static readonly DependencyProperty MemberInfoProperty = DependencyProperty.Register("MemberInfo", typeof(FamilyMemberInfo), typeof(MyThumbEx));
public FamilyMemberInfo MemberInfo
{
get { return (FamilyMemberInfo)GetValue(MemberInfoProperty); }
set { SetValue(MemberInfoProperty, value); }
}
public MyThumbEx(ControlTemplate template, FamilyMemberInfo info, Point position)
{
this.MemberInfo = info;
this.DataContext = this.MemberInfo;
this.Template = template;
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
this.ApplyTextContent();
}
public void ApplyTextContent()
{
TextBlock tbName = this.Template.FindName("tbName", this) as TextBlock;
if (tbName != null)
{
tbName.Text = this.MemberInfo.Name;
}
}
}
initialize and display it on a canvas:
public MainWindow()
{
InitializeComponent();
//
FamilyMemberInfo mi = new FamilyMemberInfo();
mi.Name = "someone";
mi.ID = "id1";
MyThumbEx te = new MyThumbEx(Application.Current.Resources["BasicShape2"] as ControlTemplate, mi, new Point(0, 0));
//
this.cvMain.Children.Add(te);
}
These codes work fine, but be noticed that in the control template, I have to set Path=DataContext.NodeType, not just Path=NodeType. I'm new to WPF, and I found that normally, when I did binding without using this template stuff, I didn't need to specify the predicate 'DataContext', right? Why we need here?
Another thing I found is, I can comment out this.DataContext = this.MemberInfo, and change binding path to Path=MemberInfo.NodeType, the code still works fine. Could anyone explain that for me?
Thanks in advance!
If you dont change the DataContext manuelly, every child automatically has the DataContext of its Parent. So if your Window has f.e. the ViewModel as DataContext all of its Controls have access to the ViewModels Properties through {Binding Path=Property}.
But in case of a ControlTemplate the usual typical flow where DataContext just cascades through from the parent to child doesn’t apply here. So you have to set the DataContext first, either through Property="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DataContext.Property}" or DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DataContext}" Property="{Binding Path=Property}".
To your second point: It could be, that the ControlTemplate automatically uses the code-behind of its containing Element as DataContext, so you can use the code-behinds properties without setting the DataContext, but I am not 100% sure about this.
My control has property Buttons of type UIElementCollection. Is it possible to modify such property via triggers (specifically DataTrigger)?
I have following code:
<Setter Property="Buttons">
<Setter.Value>
<Button>A</Button>
<Button>B</Button>
</Setter.Value>
</Setter>
And I get error "The property value is set more than once". Wrapping the buttons in UIElementCollection tag doesn't work (UIElementCollection has no default contructor). If I remove the second button, I get exception that the Buttons property is not compatible with type Button.
Thanks for any help
You can use an attached behavior to modify a collection with a setter. Here is a working example based on the Panel.Children property which is also a UIElementCollection:
<Grid>
<Grid.Resources>
<Style x:Key="twoButtons" TargetType="Panel">
<Setter Property="local:SetCollection.Children">
<Setter.Value>
<x:Array Type="UIElement">
<Button Content="Button1"/>
<Button Content="Button2"/>
</x:Array>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<StackPanel Style="{StaticResource twoButtons}"/>
</Grid>
And here is the attached property SetCollection.Children:
public static class SetCollection
{
public static ICollection<UIElement> GetChildren(DependencyObject obj)
{
return (ICollection<UIElement>)obj.GetValue(ChildrenProperty);
}
public static void SetChildren(DependencyObject obj, ICollection<UIElement> value)
{
obj.SetValue(ChildrenProperty, value);
}
public static readonly DependencyProperty ChildrenProperty =
DependencyProperty.RegisterAttached("Children", typeof(ICollection<UIElement>), typeof(SetCollection), new UIPropertyMetadata(OnChildrenPropertyChanged));
static void OnChildrenPropertyChanged(object sender, DependencyPropertyChangedEventArgs e)
{
var panel = sender as Panel;
var children = e.NewValue as ICollection<UIElement>;
panel.Children.Clear();
foreach (var child in children) panel.Children.Add(child);
}
}
Edit: A workaround would be using a converter, define your Buttons in a list in some resources:
<col:ArrayList x:Key="Buttons">
<Button>A</Button>
<Button>B</Button>
</col:ArrayList>
Namespace: xmlns:col="clr-namespace:System.Collections;assembly=mscorlib"
And use a custom converter in the setter to turn it into a collection:
<Setter Property="Buttons" Value="{Binding Source={StaticResource Buttons}, Converter={StaticResource ListToUIElementCollectionConverter}}"/>
Edit: Getting this to work properly is not a trivial task since the converter needs to know the parent object for the UIElementCollection-constructor.
In the end, I decided to circumvent the issue by modifying (with triggers) individual items of the collection (individual buttons) instead of changing whole collection.
I just hide and show the buttons depending on some conditions.
Bounty Rewarded for any solid tutorial/learning resources regarding wiring up events with templated controls.
I Have a control template like this:
<Style TargetType="local:DatePicker">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:DatePicker">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}" x:Name="myDatePickerContentArea">
<StackPanel Orientation="Vertical">
<Button x:Name="myTestButton" Content="Test button" />
<telerik:RadDatePicker Style="{StaticResource VisitsReportTextBoxStyle}" Foreground="#FFFFFF" x:Name="startDate" DateTimeWatermarkContent="Start Date"/>
<telerik:RadDatePicker Style="{StaticResource VisitsReportTextBoxStyle}" x:Name="endDate" DateTimeWatermarkContent="End Date"/>
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The C# for this template is:
public class DatePicker : Control
{
public static readonly DependencyProperty StartDateSelectedDateProperty = DependencyProperty.Register("StartDateSelectedDateProperty", typeof(DateTime), typeof(DatePicker), null);
public DateTime? StartDateSelectedDate { get; set; }
public DatePicker()
{
this.DefaultStyleKey = typeof(DatePicker);
}
public override void OnApplyTemplate()
{
RadDatePicker StartDate = this.GetTemplateChild("startDate") as RadDatePicker;
StartDate.SelectionChanged += new Telerik.Windows.Controls.SelectionChangedEventHandler(StartDate_SelectionChanged);
StartDate.SelectedDate = new DateTime(2010, 01, 01);
base.OnApplyTemplate();
}
void StartDate_SelectionChanged(object sender, Telerik.Windows.Controls.SelectionChangedEventArgs e)
{
RadDatePicker temp = (RadDatePicker)sender;
StartDateSelectedDate = temp.SelectedDate;
}
}
My selectionChanged Event Doesn't Fire and I'm not sure why.
Any Ideas ?
Here is an example of using best practice with the sort of control I think you are attempting to build (see notes at end for some explanations):-
[TemplatePart(Name = DatePicker.ElementStartDate, Type = typeof(RadDatePicker))]
[TemplatePart(Name = DatePicker.ElementEndDate, Type = typeof(RadDatePicker))]
public class DatePicker : Control
{
public DatePicker()
{
this.DefaultStyleKey = typeof(DatePicker);
}
#region Template Part Names
private const string ElementStartDate = "startDate";
private const string ElementEndDate = "endDate";
#endregion
#region Template Parts
private RadDatePicker _StartDate;
internal RadDatePicker StartDate
{
get { return _StartDate; }
private set
{
if (_StartDate != null)
{
_StartDate.SelectionChanged -= StartDate_SelectionChanged;
}
_StartDate = value;
if (_StartDate != null)
{
_StartDate.SelectionChanged += StartDate_SelectionChanged;
}
}
}
private RadDatePicker _EndDate;
internal RadDatePicker EndDate
{
get { return _EndDate; }
private set
{
if (_EndDate!= null)
{
_EndDate.SelectionChanged -= EndDate_SelectionChanged;
}
_EndDate= value;
if (_EndDate!= null)
{
_EndDate.SelectionChanged += EndDate_SelectionChanged;
}
}
}
#endregion
public static readonly DependencyProperty StartDateSelectedDateProperty =
DependencyProperty.Register(
"StartDateSelectedDateProperty",
typeof(DateTime?),
typeof(DatePicker),
new PropertyMetaData(new DateTime(2010, 01, 01)));
public DateTime? StartDateSelectedDate
{
get { return (DateTime?)GetValue(StartDateSelectedDateProperty); }
set { SetValue(StartDateSelectedDateProperty)}
}
public static readonly DependencyProperty EndDateSelectedDateProperty =
DependencyProperty.Register(
"EndDateSelectedDateProperty",
typeof(DateTime?),
typeof(DatePicker),
new PropertyMetaData(new DateTime(2010, 01, 01)));
public DateTime? EndDateSelectedDate
{
get { return (DateTime?)GetValue(EndDateSelectedDateProperty); }
set { SetValue(EndDateSelectedDateProperty)}
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
StartDate = GetTemplateChild(ElementStartDate) as RadDatePicker;
EndDate = GetTemplateChild(ElementEndDate) as RadDatePicker;
}
void StartDate_SelectionChanged(object sender, Telerik.Windows.Controls.SelectionChangedEventArgs e)
{
// Do stuff with StartDate here
}
void EndDate_SelectionChanged(object sender, Telerik.Windows.Controls.SelectionChangedEventArgs e)
{
// Do stuff with EndDate here
}
}
The template Xaml should look like:-
<Style TargetType="local:DatePicker">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:DatePicker">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}" x:Name="myDatePickerContentArea">
<StackPanel Orientation="Vertical">
<Button x:Name="myTestButton" Content="Test button" />
<telerik:RadDatePicker x:Name="startDate"
Style="{StaticResource VisitsReportTextBoxStyle}"
Foreground="#FFFFFF"
DateTimeWatermarkContent="Start Date"
SelectedDate="{TemplateBinding StartDateSelectedDate}"
/>
<telerik:RadDatePicker x:Name="endDate"
Style="{StaticResource VisitsReportTextBoxStyle}"
DateTimeWatermarkContent="End Date"
SelectedDate="{TemplateBinding EndDateSelectedDate}"
/>
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Some Explanations
A key problem your original code had was that it hadn't implemented the dependency properties correctly. Note that properties now use GetValue and SetValue, also that the property meta data is used to assign the default rather than attempting to set in in onapplytemplate.
With the properties correctly implemented the template binding should work and in fact we're done as far as getting what appears to be your original intent, hence I've left out any actual code in the event handlers.
Create constants in the code to hold the names of key template parts that you want to interact with, this allows for name changes to be less expensive to make.
Add TemplatePart attributes to the class to indicate the key elements that the code expects to find, what their names should be and what base type they are expected to have. This allows for a designer to re-template an existing control, as long the declared template parts are present somewher the control should function correctly even if its UI is radically altered.
If you need to attach event handlers for some elements create a field to hold a reference to the element and then create a property to wrap round it. The property setter should then detach and attach the event handlers as you see in the code.
Make sure bae.OnApplyTemplate is called in the override of OnApplyTemplate then as you can see its quite straight forward to assign the above created properties.
I don't have the RadDatePicker so I can't test, my only outstanding concern is where the DateTime? is the correct type for the SelectedDate property. Certainly if it is its an improvement over the Microsoft offering which seems to have drop the ball on this typical data entry requirement.
I may only guess that the problem is that for OnApplyTemplate method Implementers should always call the base implementation before their own implementation.
The other thing is that from your code it looks like it's better to use TemplateBinding(Archive)(V4) in the template xaml
<telerik:RadDatePicker SelectedDate={TemplateBinding StartDateSelectedDate}
Style="{StaticResource VisitsReportTextBoxStyle}"
Foreground="#FFFFFF" x:Name="startDate"
DateTimeWatermarkContent="Start Date"/>