You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF中如何访问样式内Popup属性并实现TimePicker选中后关闭

解决Xceed Toolkit TimePicker选中时间后自动关闭Popup的问题

问题说明

在WPF项目中使用Xceed Toolkit的TimePicker控件,时间选择ListBox通过Popup展示,由ToggleButton控制开关,且Popup的StaysOpen设为False(点击外部可关闭)。需求是选中时间选项后自动关闭Popup,但遇到以下问题:

  • 后台代码无法直接访问App.xaml样式中定义的Popup元素
  • 不清楚如何用更简便的XAML方式实现该功能

方法一:XAML纯实现(推荐)

核心思路:利用触发器,在ListBoxItem被选中时,修改ToggleButton的IsChecked状态(Popup的IsOpen已绑定到该状态),从而自动关闭Popup。

修改App.xaml中TimePickerStyle内的ListBox.ItemContainerStyle,在ControlTemplate.Triggers中添加如下触发器:

<Style x:Key="TimePickerStyle">
<Setter Property="Template">
...
    <ToggleButton x:Name="_timePickerToggleButton"> ... </ToggleButton>
                                
    <Popup x:Name="PART_Popupx"
           AllowsTransparency="True"
           IsOpen="{Binding IsChecked, ElementName=_timePickerToggleButton}"
           StaysOpen="False"
           ToolTip="">
                                    
          <Border>
                <Grid>
                     <ScrollViewer>
                            <ListBox x:Name="PART_TimeListItems">
                                   <ListBox.ItemContainerStyle>
                                       <Style TargetType="{x:Type ListBoxItem}">
                                           <Setter Property="Padding" Value="4,3" />
                                           <Setter Property="Template">
                                                 <Setter.Value>
                                                     <ControlTemplate TargetType="{x:Type ListBoxItem}">
                                                         <!-- 原有模板内容保留 -->
                                                         <ControlTemplate.Triggers>
                                                             <!-- 原有触发器保留 -->
                                                             <!-- 新增:选中项时关闭Popup -->
                                                             <Trigger Property="IsSelected" Value="True">
                                                                 <Setter TargetName="_timePickerToggleButton" 
                                                                         Property="IsChecked" 
                                                                         Value="False"
                                                                         RelativeSource="{RelativeSource AncestorType={x:Type toolkit:TimePicker}}" />
                                                             </Trigger>
                                                         </ControlTemplate.Triggers>
                                                     </ControlTemplate>
                                                 </Setter.Value>
                                           </Setter>
                                     </ListBox.ItemContainerStyle>
                             </ListBox>
                       </ScrollViewer>
                 </Grid>
            </Border>
     </Popup>

原理说明

通过RelativeSource找到父级的TimePicker控件,直接修改其模板内ToggleButton的IsChecked状态为False,由于Popup的IsOpen绑定到该状态,会自动关闭。这种方式完全符合WPF样式分离的设计原则,无需后台代码干预。


方法二:后台代码实现(可视化树查找元素)

如果需要通过后台代码实现,核心是通过可视化树遍历,找到TimePicker模板内的ToggleButton或Popup。

步骤1:修改XAML事件绑定

将原TextBoxBase.TextChanged替换为TimePicker的ValueChanged事件(更精准,仅在时间选中时触发):

<toolkit:TimePicker x:Name="tp"
         Grid.Column="2" Kind="Local" 
         Background="White" 
         Value="{Binding ReminderTime, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
         Style="{StaticResource TimePickerStyle}"  
         ValueChanged="TimePicker_ValueChanged" />

步骤2:后台代码实现

private void TimePicker_ValueChanged(object sender, RoutedPropertyChangedEventArgs<DateTime?> e)
{
    var timePicker = sender as toolkit:TimePicker;
    if (timePicker == null || e.NewValue == null) return;

    // 查找模板内的ToggleButton并关闭Popup
    var toggleButton = FindVisualChild<ToggleButton>(timePicker, "_timePickerToggleButton");
    toggleButton?.SetValue(ToggleButton.IsCheckedProperty, false);

    // 也可直接查找Popup关闭
    // var popup = FindVisualChild<Popup>(timePicker, "PART_Popupx");
    // popup?.SetValue(Popup.IsOpenProperty, false);
}

// 可视化树查找辅助方法
private T FindVisualChild<T>(DependencyObject parent, string elementName) where T : FrameworkElement
{
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
    {
        var child = VisualTreeHelper.GetChild(parent, i);
        if (child is T targetElement && targetElement.Name == elementName)
        {
            return targetElement;
        }
        var result = FindVisualChild<T>(child, elementName);
        if (result != null) return result;
    }
    return null;
}

原理说明

通过FindVisualChild方法遍历TimePicker的可视化树,定位到模板内的ToggleButton或Popup,修改其状态实现关闭。注意需确保模板内元素的Name与代码中查找的名称完全一致。


注意事项

  • 确保模板内ToggleButton(_timePickerToggleButton)和Popup(PART_Popupx)的Name属性正确,否则无法找到目标元素
  • XAML方式更简洁且符合WPF设计理念,优先推荐使用
  • 后台代码方式尽量避免直接操作UI元素,仅在特殊场景下使用

内容的提问来源于stack exchange,提问作者Eth

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 13:16:00