开发者

How to add events to templated control in silverlight?

开发者 https://www.devze.com 2023-01-28 02:26 出处:网络
Bounty Rewarded for any solid tutorial/learning resources regarding wiring up events with templated controls.

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:RadDate开发者_如何学GoPicker 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"/>
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号