Yes, the "local value" in the precedence list only refers to properties set on elements outside of templates. The relevant part of the precedence list is 4b:
4. TemplatedParent template properties. An element has a
TemplatedParent if it was created as
part of a template (a ControlTemplate
or DataTemplate). For details on when
this applies, see TemplatedParent
later in this topic. Within the
template, the following precedence
applies:
a. Triggers from the TemplatedParent
template.
b. Property sets (typically through
XAML attributes) in the
TemplatedParent template.
Property values set within the template are a lower precedence than triggers in the template, and both of these are lower precedence than local values.
You can see how a value was set by calling DependencyPropertyHelper.GetValueSource and checking the BaseValueSource property. Values set outside of a template will have a source of "Local" while values inside of a template will have a source of "ParentTemplate".
Having them as separate sources also means that the property system can keep track of the local value and the parent template value separately. If you set a local value on a property that has a value from a template and later call ClearValue, it will revert to the value set by the template.
Here is an example that demonstrates a local value overriding a value from the template. Create a UserControl with the code below and add it to a Window. It has a blue rectangle that changes to green when the mouse is anywhere over the control. If you click "Set", the code will set a local value on the rectangle that will override both values. If you click "Clear", it will clear the local value and restore the values from the template. You can click "Display" to see the current value source (you will need to press the button with the keyboard to see ParentTemplate since having the mouse over the button will set off the trigger).
XAML:
<UserControl
x:Class="WpfApplication1.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<UserControl.Template>
<ControlTemplate>
<StackPanel Background="Transparent">
<Button Click="Display_Click" Content="Display"/>
<Button Click="Set_Click" Content="Set"/>
<Button Click="Clear_Click" Content="Clear"/>
<Rectangle Width="100" Height="100"
Fill="Blue" Name="PART_Rectangle"/>
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="PART_Rectangle"
Property="Fill" Value="Green"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</UserControl.Template>
</UserControl>
Code-behind:
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
rectangle = Template.FindName("PART_Rectangle", this) as Rectangle;
}
private Rectangle rectangle;
private void Display_Click(object sender, RoutedEventArgs e)
{
var source = DependencyPropertyHelper.GetValueSource(
rectangle, Rectangle.FillProperty);
MessageBox.Show(string.Format("Value {0}; Source {1}",
rectangle.Fill, source.BaseValueSource));
}
private void Set_Click(object sender, RoutedEventArgs e)
{
rectangle.Fill = Brushes.Red;
}
private void Clear_Click(object sender, RoutedEventArgs e)
{
rectangle.ClearValue(Rectangle.FillProperty);
}
}