WPF 按钮如何允许在不丢失其核心外观的情况下设置内容?
How does a WPF button allow the content to be set without losing its core appearance?
这是一个有点愚蠢的问题,但也是一个让我困惑的问题,它是如何工作的。假设我定义了自己的 UserControl,它扩展了 ContentControl 并提供了这个:
<Grid x:Name="William">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBox Text="{Binding RelativeSource={RelativeSource Self}, Path=FontSize, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></TextBox>
<Button HorizontalAlignment="Center" Content="{Binding Time}" Grid.Row="1" CommandTarget="{Binding RelativeSource={RelativeSource AncestorType=Grid}}" Command="{x:Static local:Commands.Foo}">
</Button>
</Grid>
忽略绑定,重要的是这是我的 UserControl 的内容。
我在主 Window 中创建了一个用户控件实例,如下所示:
<local:UserControl1 x:Name="myC" Grid.Row="1" DataContext="{Binding ChildName}">
</local:UserControl1>
一切正常。现在我可以像这样覆盖用户控件中定义的内容:
<local:UserControl1 x:Name="myC" Grid.Row="1" DataContext="{Binding ChildName}">
Hello!
</local:UserControl1>
并且整个内容被替换为文本 'Hello!'
但是一个按钮允许我设置内容,但仍然保留一个按钮:
<Button x:Name="testBt">
Hello!
</Button>
谁能解释这是为什么?
已完全控制更新:
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:RoutedCommandDemo"
xmlns:dates="clr-namespace:System;assembly=mscorlib" xmlns:Linq="clr-namespace:System.Xml.Linq;assembly=System.Xml.Linq" x:Class="RoutedCommandDemo.UserControl1"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
>
<UserControl.Resources>
<Style TargetType="Button">
<Style.Setters>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<Border Background="{TemplateBinding BorderBrush}" Margin="5 5 0 0" />
<Border BorderBrush="Black" BorderThickness="1"
Background="{TemplateBinding Background}" Margin="0 0 5 5">
<ContentPresenter HorizontalAlignment="{TemplateBinding Property=HorizontalAlignment}"
VerticalAlignment="Center"/>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Background" Value="Yellow"></Setter>
<Setter Property="BorderBrush" Value="Red"></Setter>
</Style.Setters>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Pink"></Setter>
<Setter Property="BorderBrush" Value="Green"></Setter>
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType="local:UserControl1">
<Style.Setters>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:UserControl1">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<ContentPresenter Content="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding Property=HorizontalAlignment}"
VerticalAlignment="Center"/>
<TextBox Grid.Row="1" Text="{Binding RelativeSource={RelativeSource Self}, Path=FontSize, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></TextBox>
<Button Grid.Row="2" HorizontalAlignment="Center" Content="{Binding Time}" CommandTarget="{Binding RelativeSource={RelativeSource AncestorType=Grid}}" Command="{x:Static local:Commands.Foo}">
</Button>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
</UserControl.Resources>
<UserControl.CommandBindings>
<CommandBinding Command="{x:Static local:Commands.Foo}" Executed="CommandBinding_Executed"/>
</UserControl.CommandBindings>
<UserControl.InputBindings>
<KeyBinding Command="{x:Static local:Commands.Foo}" Modifiers="Control" Key="Space"></KeyBinding>
</UserControl.InputBindings>
按钮有一个控件模板。
看看这个 MSDN 页面:Button Styles and Templates。它列出了默认按钮样式。
注意以下几点:
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
...
<Border x:Name="Background" ...>
...
</Border>
<ControlPresenter Content="{TemplateBinding Content}" ... />
<Rectangle x:Name="DisabledVisualElement" ... />
<Rectangle x:Name="FocusVisualElement" ... />
...
您在 "Hello" 文本后面看到的是 Background
Border
元素。内容本身由 ContentPresenter
.
呈现
视觉主题定义了这些默认样式(因此您可以在 WinXP/Win7/Win10 等上获得不同的外观)。它们也可以被应用程序样式覆盖。
由于显而易见的原因,UserControl
没有预定义的外观。
这是一个有点愚蠢的问题,但也是一个让我困惑的问题,它是如何工作的。假设我定义了自己的 UserControl,它扩展了 ContentControl 并提供了这个:
<Grid x:Name="William">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBox Text="{Binding RelativeSource={RelativeSource Self}, Path=FontSize, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></TextBox>
<Button HorizontalAlignment="Center" Content="{Binding Time}" Grid.Row="1" CommandTarget="{Binding RelativeSource={RelativeSource AncestorType=Grid}}" Command="{x:Static local:Commands.Foo}">
</Button>
</Grid>
忽略绑定,重要的是这是我的 UserControl 的内容。
我在主 Window 中创建了一个用户控件实例,如下所示:
<local:UserControl1 x:Name="myC" Grid.Row="1" DataContext="{Binding ChildName}">
</local:UserControl1>
一切正常。现在我可以像这样覆盖用户控件中定义的内容:
<local:UserControl1 x:Name="myC" Grid.Row="1" DataContext="{Binding ChildName}">
Hello!
</local:UserControl1>
并且整个内容被替换为文本 'Hello!'
但是一个按钮允许我设置内容,但仍然保留一个按钮:
<Button x:Name="testBt">
Hello!
</Button>
谁能解释这是为什么?
已完全控制更新:
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:RoutedCommandDemo"
xmlns:dates="clr-namespace:System;assembly=mscorlib" xmlns:Linq="clr-namespace:System.Xml.Linq;assembly=System.Xml.Linq" x:Class="RoutedCommandDemo.UserControl1"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
>
<UserControl.Resources>
<Style TargetType="Button">
<Style.Setters>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<Border Background="{TemplateBinding BorderBrush}" Margin="5 5 0 0" />
<Border BorderBrush="Black" BorderThickness="1"
Background="{TemplateBinding Background}" Margin="0 0 5 5">
<ContentPresenter HorizontalAlignment="{TemplateBinding Property=HorizontalAlignment}"
VerticalAlignment="Center"/>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Background" Value="Yellow"></Setter>
<Setter Property="BorderBrush" Value="Red"></Setter>
</Style.Setters>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Pink"></Setter>
<Setter Property="BorderBrush" Value="Green"></Setter>
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType="local:UserControl1">
<Style.Setters>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:UserControl1">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<ContentPresenter Content="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding Property=HorizontalAlignment}"
VerticalAlignment="Center"/>
<TextBox Grid.Row="1" Text="{Binding RelativeSource={RelativeSource Self}, Path=FontSize, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></TextBox>
<Button Grid.Row="2" HorizontalAlignment="Center" Content="{Binding Time}" CommandTarget="{Binding RelativeSource={RelativeSource AncestorType=Grid}}" Command="{x:Static local:Commands.Foo}">
</Button>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
</UserControl.Resources>
<UserControl.CommandBindings>
<CommandBinding Command="{x:Static local:Commands.Foo}" Executed="CommandBinding_Executed"/>
</UserControl.CommandBindings>
<UserControl.InputBindings>
<KeyBinding Command="{x:Static local:Commands.Foo}" Modifiers="Control" Key="Space"></KeyBinding>
</UserControl.InputBindings>
按钮有一个控件模板。
看看这个 MSDN 页面:Button Styles and Templates。它列出了默认按钮样式。
注意以下几点:
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
...
<Border x:Name="Background" ...>
...
</Border>
<ControlPresenter Content="{TemplateBinding Content}" ... />
<Rectangle x:Name="DisabledVisualElement" ... />
<Rectangle x:Name="FocusVisualElement" ... />
...
您在 "Hello" 文本后面看到的是 Background
Border
元素。内容本身由 ContentPresenter
.
视觉主题定义了这些默认样式(因此您可以在 WinXP/Win7/Win10 等上获得不同的外观)。它们也可以被应用程序样式覆盖。
由于显而易见的原因,UserControl
没有预定义的外观。