如何在silverlight中为模板化控件添加事件?

时间:2010-12-01 22:59:28

标签: silverlight silverlight-4.0

Bounty奖励任何有关使用模板化控件连接事件的实用教程/学习资源。

我有一个这样的控制模板:

<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>

此模板的C#是:

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;
    }


}

我的选择更改事件不会触发,我不知道为什么。 任何想法?

2 个答案:

答案 0 :(得分:4)

以下是使用我认为您正在尝试构建的控件的最佳实践的示例(请参阅最后的注释以获得一些解释): -

[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
    }     
} 

模板Xaml应如下所示: -

<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>

一些解释

  • 原始代码存在的一个关键问题是它没有正确实现依赖项属性。请注意,属性现在使用GetValueSetValue,并且属性元数据用于分配默认值而不是尝试在onapplytemplate中设置。
  • 在正确实现属性的情况下,模板绑定应该可以正常工作,事实上我们已经完成了看似您原始意图的事情,因此我在事件处理程序中遗漏了任何实际代码。
  • 在代码中创建常量以保存您要与之交互的关键模板部件的名称,这样可以降低名称更改的成本。
  • 向类中添加TemplatePart属性,以指示代码期望找到的关键元素,它们的名称应该是什么以及它们应具有的基本类型。这允许设计者重新模板化现有控件,只要声明的模板部件存在,控件应该正确运行,即使其UI被彻底改变。
  • 如果需要为某些元素附加事件处理程序,请创建一个字段来保存对该元素的引用,然后创建一个包围它的属性。然后,属性设置器应该分离并附加事件处理程序,如代码中所示。
  • 确保在OnApplyTemplate的覆盖中调用bae.OnApplyTemplate,然后您可以看到它非常直接地分配上面创建的属性。
  • 我没有RadDatePicker,所以我无法测试,我唯一关注的问题是DateTime?是SelectedDate属性的正确类型。当然,如果它是对微软产品的改进,似乎已经放弃了这个典型的数据输入要求。

答案 1 :(得分:3)

我可能只会猜测问题出在OnApplyTemplate方法Implementers should always call the base implementation before their own implementation.上 另一件事是,从您的代码看,最好在模板xaml中使用TemplateBindingArchive)(V4

<telerik:RadDatePicker SelectedDate={TemplateBinding StartDateSelectedDate}
                       Style="{StaticResource VisitsReportTextBoxStyle}" 
                       Foreground="#FFFFFF"  x:Name="startDate" 
                       DateTimeWatermarkContent="Start Date"/>