自定义 WPF 控件中的数据绑定

Data binding in custom WPF controls

我完全无法尝试将图像绑定到我的自定义 WPF 扩展器。

我在这里找到了创建扩展器模板的示例:https://www.codeproject.com/Articles/248112/Templating-WPF-Expander-Control 并尝试对其进行编辑以使用图像而不是扩展器图标。

这是我的扩展按钮自定义模板(我在这里添加了一个图像源,因此它可以在直接资源路径下正常工作,而不是绑定):

<ControlTemplate x:Key="SimpleExpanderButtonTemp" 
                TargetType="{x:Type ToggleButton}">
            <Border x:Name="ExpanderButtonBorder"
                Background="{TemplateBinding Background}"
                BorderBrush="{TemplateBinding BorderBrush}"
                BorderThickness="{TemplateBinding BorderThickness}"
                Padding="{TemplateBinding Padding}"
                >
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition Width="*"/>
                    </Grid.ColumnDefinitions>
                    <Image 
                        Height="35"
                        Width="35"
                        Source="{Binding Path = ImageSource, 
                        RelativeSource={RelativeSource TemplatedParent}}">
                    </Image>
                    
                    <ContentPresenter x:Name="HeaderContent"
                          Grid.Column="1"
                          Margin="4,0,0,0"
                          ContentSource="Content"/>
                </Grid>
            </Border>
            <ControlTemplate.Triggers>
                <!-- MouseOver, Pressed behaviours-->
                <Trigger Property="IsMouseOver"
                         Value="true">
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>

之后,我将模板添加到扩展器本身:

<ControlTemplate x:Key="SidePanelExpander" TargetType="Expander">
            <DockPanel>
                <ToggleButton x:Name="ExpanderButton"
                    DockPanel.Dock="Top"
                    ImageSource="{Binding Path = ImageSource,
                    RelativeSource={RelativeSource TemplatedParent}}"
                    Template="{StaticResource SimpleExpanderButtonTemp}"
                    Content="{TemplateBinding Header}"
                    IsChecked="{Binding Path=IsExpanded, 
                    RelativeSource={RelativeSource TemplatedParent}}"
                    OverridesDefaultStyle="True"
                    Padding="1.5,0">
                </ToggleButton>
                <ContentPresenter x:Name="ExpanderContent"
                          Visibility="Collapsed"
                          DockPanel.Dock="Bottom"/>
            </DockPanel>
            <ControlTemplate.Triggers>
                <Trigger Property="IsExpanded" Value="True">
                    <Setter TargetName="ExpanderContent" 
              Property="Visibility" Value="Visible"/>
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>

然后我尝试以这种方式使用它:

        <Expander ExpandDirection="Right"
                  Template="{StaticResource SidePanelExpander}"
                  ImageSource="../Res/Images/engine.png"
                  >

我猜想通过模板进行数据绑定转发有一些困难,但不知道如何解决。

正如 Clemens 在评论中所说,ToggleButtonExpander 没有一个名为 ImageSource 的 属性,因此此代码永远无法工作。执行此操作的“正确”方法是创建自定义控件,但快速修复(hack)是使用标签 属性:

指定图像路径

在“SimpleExpanderButtonTemp”模板中,按如下方式更改 Image 元素源:

<Image Height="35"
       Width="35"
       Source="{Binding Path=Tag, RelativeSource={RelativeSource TemplatedParent}}" />

接下来,在“SidePanelExpander”模板 ToggleButton 中,删除“ImageSource=...”行并将其替换为:

Tag="{TemplateBinding Tag}"

最后,在控件本身中,指定您的图像:

<Expander Tag="../Res/Images/engine.png"
          ...

此外,在第一个模板中,我注意到您在 Border 控件的某些属性(背景、边框刷、边框厚度)上使用了 TemplateBindings。这些也行不通。要解决此问题,请将这些相同的行复制到第二个模板的 ToggleButton 控件,即

<ToggleButton x:Name="ExpanderButton"
              Background="{TemplateBinding Background}"
              BorderBrush="{TemplateBinding BorderBrush}"
              BorderThickness="{TemplateBinding BorderThickness}"
              ...

您现在可以在控件本身中指定(比方说)背景颜色:

<Expander Background="Blue"
          ...

ToggleButton 上的 TemplateBindings 就像垫脚石,允许 属性 值从控件本身传递到 ToggleButton,然后传递到 Border。