In almost all programming languages, names are not globally unique, they are unique only relative to other names in the same name scope. In C++ and C#, a name scope is roughly what goes between curly braces -- { }. And in C++ and C#, namescopes nest -- if the compiler can't find the name in the nearest namescope { }, it will look in the containing namescope.

Xaml names have many of the same issues. In <Button Name="foo">, foo is not unique to the whole program, there could be other xaml files with the same name. And you can instantiate that xaml file multiple times (e.g., multiple windows). And through the use of templates, you can even get the same element multiple times in the same file:

<Window>
    <Window.Resources>
        <ControlTemplate x:Key="template"  TargetType="{x:Type Button}">
            <Rectangle Name="foo"/>
        </ControlTemplate
    </Window.Resources>

    <Button Template="{StaticResource template}"/>
    <Button Template="{StaticResource template}"/>

</Window>

Once those templates are instantiated, there's two rectangles named "foo"!

WPF handles this with the interface INameScope, which has methods FindName, RegisterName, and UnregisterName. In WPF, namescopes are always associated with a single element, although there's nothing in the namescope design that requires that. The root element in each xaml file gets its own name scope. Instantiated templates each have their own name scope (in the example above, it contains exactly one name -- "foo"). Styles also get their own name scope, mostly so we can name the parts of storyboards. And ResourceDictionary has its own degenerate name scope, a "throw scope", which throws an exception if you try to add a name to it, to help avoid confusion between x:Name and x:Key.

FrameworkElement also has FindName, RegisterName and UnregisterName methods. If the element owns a name scope, the element methods simply call into the name scope's methods. Otherwise, WPF walks up the (logical) tree looking for the nearest namescope. I was a little hesitant to make it so easy to register with a distance scope -- if you're not sure what name scope your registering with, you can't really be sure your name is unique -- but, you need a name to use the storyboard APIs, and in most programs it's fairly easy to be "unique enough" with your names, so we went with it.

I alluded to the similarity between xaml and C# namescopes -- one important difference is that in xaml, namescopes don't nest -- if WPF doesn't find the name you're looking for in the first name scope, it doesn't go out to a bigger name scope. But that's a post for another day...