【问题标题】:Change WPF Combobox arrow using a data trigger使用数据触发器更改 WPF 组合框箭头
【发布时间】:2016-10-24 18:37:29
【问题描述】:

我正在使用我在 CodeProject [http://www.codeproject.com/Articles/563862/Multi-Select-ComboBox-in-WPF] 上找到的多选组合框。

我正在尝试根据是否选择了所有项目来更改箭头的形状。但是我一直无法正确引用 setter 中的 x:Name of Arrow。

这是我一直在尝试修改的代码:

<UserControl x:Class="Z_Sys_UI.System.MultiSelectComboBox"
         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" 
         mc:Ignorable="d" >
<ComboBox
    x:Name="MultiSelectCombo"  
    SnapsToDevicePixels="True"
    OverridesDefaultStyle="True"
    ScrollViewer.HorizontalScrollBarVisibility="Auto"
    ScrollViewer.VerticalScrollBarVisibility="Auto"
    ScrollViewer.CanContentScroll="True"
    IsSynchronizedWithCurrentItem="True"
                       >
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <CheckBox Content="{Binding Title}"
                      IsChecked="{Binding Path=IsSelected, Mode=TwoWay}"
                      Tag="{RelativeSource FindAncestor, AncestorType={x:Type ComboBox}}"
                       Click="CheckBox_Click"           />
        </DataTemplate>
    </ComboBox.ItemTemplate>
    <ComboBox.Template>
        <ControlTemplate TargetType="ComboBox">
            <Grid >
                <ToggleButton 
                    x:Name="ToggleButton" 
                   Grid.Column="2" IsChecked="{Binding Path=IsDropDownOpen,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}"
                    Focusable="false"                           
                    ClickMode="Press" HorizontalContentAlignment="Left" >
                    <ToggleButton.Template>
                        <ControlTemplate>
                            <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="*"/>
                                    <ColumnDefinition Width="18"/>
                                </Grid.ColumnDefinitions>
                                <Border
              x:Name="Border" 
              Grid.ColumnSpan="2"
              CornerRadius="2"
              Background="White"
              BorderBrush="Black"
              BorderThickness="1,1,1,1" />
                                <Border 
                x:Name="BorderComp" 
              Grid.Column="0"
              CornerRadius="2" 
              Margin="1" 
             Background="White"
              BorderBrush="Black"
              BorderThickness="0,0,0,0" >
                                    <TextBlock Text="{Binding Path=Text,RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}" 
                                           Background="White" Padding="3" />
                                </Border>
              <Path 
              x:Name="Arrow"
              Grid.Column="1"     
              Fill="Black"
              HorizontalAlignment="Center"
              VerticalAlignment="Center"
              Data="M 0 0 L 4 4 L 8 0 Z">
                                </Path>
                            </Grid>
                        </ControlTemplate>
                    </ToggleButton.Template>
                </ToggleButton>
                <Popup 
                    Name="Popup"
                    Placement="Bottom"                        
                    AllowsTransparency="True" 
                    Focusable="False"  IsOpen="{TemplateBinding IsDropDownOpen}"
                    PopupAnimation="Slide">
                    <Grid 
                              Name="DropDown"
                              SnapsToDevicePixels="True"  
                        MinWidth="{TemplateBinding ActualWidth}"
                              MaxHeight="{TemplateBinding MaxDropDownHeight}">
                        <Border 
                                x:Name="DropDownBorder" 
                               BorderThickness="1" Background="White"
                                BorderBrush="Black"/>
                        <ScrollViewer Margin="4,6,4,6" SnapsToDevicePixels="True" DataContext="{Binding}">
                            <StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" />
                        </ScrollViewer>
                    </Grid>
                </Popup>
            </Grid>
            <ControlTemplate.Triggers>
                <Trigger Property="HasItems" Value="false">
                    <Setter TargetName="DropDownBorder" Property="MinHeight" Value="95"/>
                </Trigger>
                <Trigger SourceName="Popup" Property="Popup.AllowsTransparency" Value="true">
                    <Setter TargetName="DropDownBorder" Property="CornerRadius" Value="4"/>
                    <Setter TargetName="DropDownBorder" Property="Margin" Value="0,2,0,0"/>
                </Trigger>
                <DataTrigger Binding="{Binding Path=SelectAll, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=UserControl}}" Value="false" >
                    <Setter TargetName="Arrow" Property="Data" Value="M 0 0 L 2 2 L 8 0 Z" />
                </DataTrigger>
            </ControlTemplate.Triggers>

        </ControlTemplate>
    </ComboBox.Template>
</ComboBox>

现在它给出了错误,说名称箭头无法识别,成员数据无法识别或无法访问。

我尝试触发的 SelectAll 路径也可能不起作用。 CodeProject 代码似乎没有完全实现该属性。我稍后会处理这种可能性。

提前感谢您的任何回答或建议。

【问题讨论】:

  • 更改存在于 ToggleButton 模板中的控件的触发器必须在 ToggleButton 模板本身中。但是它是如何绑定到 ComboBox 的属性的呢?如果您无法让 AncestorType 绑定在 ToggleButton 的 ControlTemplate 内的 DataTrigger 上工作,我会尝试使用您拥有的触发器并更改 ToggleButton 的整个模板。只需制作两个 ToggleButton ControlTemplate 副本,每个版本对应一个箭头。

标签: wpf combobox


【解决方案1】:

名称Arrow 超出了ComboBox ControlTemplate 的范围,因为它是在ToggleButton ControlTemplate 中定义的。解决方案很简单:只需将触发器放在目标控件在范围内的模板中。

<ToggleButton.Template>
    <ControlTemplate>
        <Grid>

            <!-- snip snip snip -->
            <!-- snip snip snip -->
            <!-- snip snip snip -->

            <Path 
                x:Name="Arrow"
                Grid.Column="1"     
                Fill="Black"
                HorizontalAlignment="Center"
                VerticalAlignment="Center"
                Data="M 0 0 L 4 4 L 8 0 Z"
                >
            </Path>
        </Grid>
        <ControlTemplate.Triggers>
            <DataTrigger 
                Binding="{Binding Path=SelectAll, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=UserControl}}" 
                Value="false" >
                <Setter 
                    TargetName="Arrow" 
                    Property="Data" 
                    Value="M 0 0 L 2 2 L 8 0 Z"  
                    />
            </DataTrigger>
        </ControlTemplate.Triggers>
    </ControlTemplate>
</ToggleButton.Template>

我假设SelectAll 是一个布尔依赖属性,并且是MultiSelectComboBox 的成员,因为您正在使用它似乎暗示了这一点。这是我的依赖属性定义:

    public static readonly DependencyProperty SelectAllProperty =
        DependencyProperty.Register("SelectAll", typeof(bool), typeof(MultiSelectComboBox),
            new PropertyMetadata(false));

这是我使用的测试 XAML:

<StackPanel
    Orientation="Vertical"
    >
    <CheckBox Content="SelectAll" x:Name="SelectAllCheckBox" />
    <local:MultiSelectComboBox 
        SelectAll="{Binding IsChecked, ElementName=SelectAllCheckBox}" />
</StackPanel>

【讨论】:

  • 到目前为止一切顺利,谢谢。将触发器放在目标控件在范围内的模板中修复了我得到的 xaml 错误。 SelectAll 是一个布尔依赖属性,我将在下一步中查看它是否有效。
  • 一切都好。我实施了您的 xaml 更改,并且在我第一次尝试时它就起作用了。我已经对现有代码进行了一些修改,以确保正确设置 SelectAll。
  • @dev1998 好消息!
  • Data="M 0 0 L 4 4 L 8 0 Z" 是什么意思?
  • @Hacki 询问模组。
猜你喜欢
  • 1970-01-01
  • 2019-05-17
  • 2018-02-15
  • 1970-01-01
  • 2016-07-10
  • 2013-02-28
  • 1970-01-01
  • 1970-01-01
  • 2018-08-08
相关资源
最近更新 更多