需要用到code behind
注意要给需要访问的元素命名x:Name="PART_TextBlock"
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CustomControlLib"> <Style TargetType="{x:Type local:MyControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:MyControl}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<StackPanel>
<TextBlock x:Name="PART_TextBlock" />
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
custom control的程序部分 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes; namespace CustomControlLib
{ public class MyControl : Button
{
private const string TextBlockPart = "PART_TextBlock";
TextBlock textBlock;
static MyControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyControl), new FrameworkPropertyMetadata(typeof(MyControl)));
}
public override void OnApplyTemplate() //OnApplyTemplate get called everytime a template is applied to the control,control update
{
base.OnApplyTemplate(); //Button有自己的OnApplyTemplate我们需要call这个beofre call我们自己写的OnApplyTemplate方法
if (textBlock != null) //避免memory leak每次call OnApplyTemplate方法时都给同一个textBlock加上event
{
textBlock.TextInput -= new TextCompositionEventHandler(textBlock_TextInput);
} textBlock = GetTemplateChild(TextBlockPart) as TextBlock;
if (textBlock != null)
{
textBlock.Text = "Set from code";
textBlock.TextInput +=new TextCompositionEventHandler(textBlock_TextInput);
} } private void textBlock_TextInput(object sender, TextCompositionEventArgs e)
{ }
}
}
使用该control
<Window x:Class="CustomControlDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cc="clr-namespace:CustomControlLib;assembly=CustomControlLib"
Title="MainWindow"
Width="525"
Height="350">
<Grid>
<cc:MyControl />
</Grid>
</Window>
改进:上面的方法不好,设想如果controlTemaplte里有很多element都需要访问,每一个元素都需要后台程序这样访问的话,会很乱
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes; namespace CustomControlLib
{
[TemplatePart(Name = TextBlockPart, Type = typeof(TextBlock))] //告诉使用template的作者这里x:Name为PART_TextBlock的control一定要是TextBlock类型的
public class MyControl : Button
{
private const string TextBlockPart = "PART_TextBlock";
TextBlock _textBlock; //避免每一次call OnApplyTemplate都在方法体里创建一个TextBlock,在方法前定义一个变量来储存
protected TextBlock TextBlock
{
get {return _textBlock; }
set
{
if (_textBlock != null) //避免memory leak每次call OnApplyTemplate方法时都给同一个textBlock加上event
{
_textBlock.TextInput -= new TextCompositionEventHandler(textBlock_TextInput);
} _textBlock = value; if (_textBlock != null)
{
_textBlock.Text = "Set from code";
_textBlock.TextInput += new TextCompositionEventHandler(textBlock_TextInput);
}
}
}
static MyControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyControl), new FrameworkPropertyMetadata(typeof(MyControl)));
}
public override void OnApplyTemplate() //OnApplyTemplate get called everytime a template is applied to the control,control update
{
base.OnApplyTemplate(); //Button有自己的OnApplyTemplate我们需要call这个beofre call我们自己写的OnApplyTemplate方法 TextBlock = GetTemplateChild(TextBlockPart) as TextBlock; //每次call都赋值属性
} private void textBlock_TextInput(object sender, TextCompositionEventArgs e)
{ }
}
}
TemplatePart(Name="PART_Decrease", Type=typeof(RepeatButton))
一直没明白这是干嘛用的,搜了一下,记载一下。
以Button的定义为例:

namespace System.Windows.Controls
{
// Summary:
// Represents a button control, which reacts to the Click event.
[TemplatePart(Name = "Normal State", Type = typeof(Storyboard))]
[TemplatePart(Name = "MouseOver State", Type = typeof(Storyboard))]
[TemplatePart(Name = "RootElement", Type = typeof(FrameworkElement))]
[TemplatePart(Name = "Pressed State", Type = typeof(Storyboard))]
[TemplatePart(Name = "FocusVisualElement", Type = typeof(UIElement))]
[TemplatePart(Name = "Disabled State", Type = typeof(Storyboard))]
public class Button : ButtonBase
{
// Summary:
// Initializes a new instance of the Button class.
public Button();
// Summary:
// Apply a template to the Button.
protected override void OnApplyTemplate();
//
// Summary:
// Called when the IsEnabled property changes.
//
// Parameters:
// isEnabled:
// New value of the IsEnabled property.
protected override void OnIsEnabledChanged(bool isEnabled);
}
}

[TemplatePart(Name = "Normal State", Type = typeof(Storyboard))] 这种东东是做什么用的 , 其实这是一种契约 , 是一种推荐的控件设计模式(只是推荐) , 意思是告诉要来写ControlTemplate的用户 , 你的ControlTemplate中需要有一个x:Name为“Normal State” , 类型为Storyboard , 当然这个类型可以是继承来的, 为什么一定要包含这些契约规定的元素 , 因为逻辑部分对这些东西进行了引用,它们将对控件的默认行为起着关键作用, 可以理解为这个控件的最基本元素 , 是实现默认行为的最小集合, 自然,你的ControlTemplate中如果没有包含契约中的内容 , 则相应的逻辑将无法实现。
所以说白了,就是提示用的.....这么写比较规范。