WPF中DataTemplate绑定ElementName生效,Style Setter中失效原因咨询
以下代码可以正常运行:
<Window.Resources> <DataTemplate x:Key="Content_Test1"> <StackPanel Orientation="Horizontal"> <Button x:Name="Button1">Mouse me</Button> <TextBlock x:Name="TextBlock1" Margin="2,0,0,0"> HELLO WOLRD <TextBlock.Style> <Style TargetType="TextBlock"> <Setter Property="Visibility" Value="Collapsed" /> <Style.Triggers> <DataTrigger Binding="{Binding ElementName=Button1, Path=IsMouseOver}" Value="False"> <Setter Property="Visibility" Value="Collapsed" /> </DataTrigger> <DataTrigger Binding="{Binding ElementName=Button1, Path=IsMouseOver}" Value="True"> <Setter Property="Visibility" Value="Visible" /> </DataTrigger> </Style.Triggers> </Style> </TextBlock.Style> </TextBlock> </StackPanel> </DataTemplate> </Window.Resources> <Grid> <ContentControl x:Name="contentControl1" ContentTemplate="{StaticResource Content_Test1}"> </ContentControl> </Grid>
而以下代码会报错:Cannot find source for binding with reference 'ElementName=Button1'
<Grid> <ContentControl x:Name="contentControl1"> <ContentControl.Style> <Style TargetType="ContentControl"> <Setter Property="Content"> <Setter.Value> <StackPanel Orientation="Horizontal"> <Button x:Name="Button1">Mouse me</Button> <TextBlock x:Name="TextBlock1" Margin="2,0,0,0"> HELLO WOLRD <TextBlock.Style> <Style TargetType="TextBlock"> <Setter Property="Visibility" Value="Collapsed" /> <Style.Triggers> <DataTrigger Binding="{Binding ElementName=Button1, Path=IsMouseOver}" Value="False"> <!--Look Here--> <Setter Property="Visibility" Value="Collapsed" /> </DataTrigger> <DataTrigger Binding="{Binding ElementName=Button1, Path=IsMouseOver}" Value="True"> <Setter Property="Visibility" Value="Visible" /> </DataTrigger> </Style.Triggers> </Style> </TextBlock.Style> </TextBlock> </StackPanel> </Setter.Value> </Setter> </Style> </ContentControl.Style> </ContentControl> </Grid>
两个示例需求一致,但第二种场景下Binding无法找到相邻元素Button1的ElementName,核心原因在于XAML资源的作用域与加载机制差异:
DataTemplate的特性:DataTemplate是专门用于生成可视化树的模板,当ContentControl应用DataTemplate时,模板内的元素会被实例化到ContentControl的可视化树中,并且模板内部形成一个独立的命名范围(Name Scope)。在这个命名范围内,ElementName绑定可以正常查找同模板内的元素(比如Button1),因为模板实例化后,这些元素处于同一个可视化树分支,命名范围是互通的。
Style Setter的限制:Style是可共享的资源(即使内联定义,加载逻辑依然遵循共享资源规则)。在Style的Setter中定义Content的Value时,这个StackPanel及其内部元素是作为"冻结"的资源存在的,并不会立即实例化到可视化树中。更关键的是,Style的资源作用域属于应用级或控件级,而非目标控件的可视化树范围。此时ElementName绑定试图查找Button1,但Button1还未被实例化到当前命名范围,且Style的资源上下文无法访问到未来才会生成的控件实例的命名范围,因此会找不到绑定源。
简单来说:DataTemplate实例化后会创建自己的命名范围,内部元素彼此可见;而Style中的Setter值是预定义的资源,在绑定解析时,目标元素还没进入可视化树,也不在同一个命名范围里,所以ElementName绑定失效。
内容的提问来源于stack exchange,提问作者Yarogleck

