【问题标题】:WpfToolkit AutoCompleteBox ContextMenu not workingWpfToolkit AutoCompleteBox ContextMenu 不起作用
【发布时间】:2023-03-19 22:44:01
【问题描述】:

在我的一个 WPF 项目中,我集成了 WPF Toolkit 的 AutoCompleteBox 控件。我需要一个自定义的Context Menu 用于这个控件,我已经使用ContextMenu 属性添加了一个。不幸的是,它没有显示自定义创建的,而是显示默认的(即剪切、复制、粘贴,剪切和复制禁用)。

为了重现问题,我创建了一个示例项目,该窗口在 Grid 内包含 2 个控件。

<Grid>
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <toolkit:AutoCompleteBox>
            <toolkit:AutoCompleteBox.ContextMenu>
                <ContextMenu>
                    <MenuItem Header="Menu Item 1"></MenuItem>
                    <MenuItem Header="Menu Item 2"></MenuItem>
                </ContextMenu>
            </toolkit:AutoCompleteBox.ContextMenu>
        </toolkit:AutoCompleteBox>
        <TextBox Grid.Row="1" >
            <TextBox.ContextMenu>
                <ContextMenu>
                    <MenuItem Header="Menu Item 1"></MenuItem>
                    <MenuItem Header="Menu Item 2"></MenuItem>
                </ContextMenu>
            </TextBox.ContextMenu>
        </TextBox>
    </Grid>

这两个控件具有相同的ContextMenu,如果我运行解决方案,我可以看到自定义创建的ContextMenu 适用于TextBox,而不适用于AutoCompleteBox

另外,我将相同的上下文菜单设置为 Grid(父控件)并将 ContextMenu="{x:Null}" 设置为 TextBox 和 AutoCompleteBox。现在ContextMenuTextBox 继承,而不是AutoCompleteBox

所以我的问题是,如何为 AutoCompleteBox 创建自定义 ContextMenu? 如果不是设计使然(AutoCompleteBox),我如何将ContextMenu 添加到从AutoCompleteBox 继承的自定义 AutoCompleteBox 控件中。 请指教。

【问题讨论】:

  • 您想要在上下文菜单中添加什么?据我所见,它是从 TextBox 继承命令。也许你应该实现自己的。
  • @Dennis - 你试过我的答案了吗?它不能解决你的问题吗?

标签: c# wpf wpftoolkit


【解决方案1】:

Toolkits AutoCompleteBox 的问题是,他们错过了将 ContextMenu 传递给其可视化树的内部元素。我已经编辑了 AutoCompleteBox 的模板。当我在 AutoCompleteBox 的模板内的 AutoCompleteBox 的 ContextMenu 和 TextBox 的 ContextMenu 之间添加 TemplateBinding 时,它工作正常。

请找到代码修复:

  <Grid>
    <Grid.Resources>
        <Style TargetType="toolkit:AutoCompleteBox" x:Key="AutoCompleteBoxStyle">
            <Setter Property="IsTabStop" Value="False" />
            <Setter Property="Padding" Value="2" />
            <Setter Property="BorderThickness" Value="1" />
            <Setter Property="BorderBrush">
                <Setter.Value>
                    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                        <GradientStop Color="#FFA3AEB9" Offset="0" />
                        <GradientStop Color="#FF8399A9" Offset="0.375" />
                        <GradientStop Color="#FF718597" Offset="0.375" />
                        <GradientStop Color="#FF617584" Offset="1" />
                    </LinearGradientBrush>
                </Setter.Value>
            </Setter>
            <Setter Property="Background" Value="#FFFFFFFF" />
            <Setter Property="Foreground" Value="#FF000000" />
            <Setter Property="MinWidth" Value="45" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="toolkit:AutoCompleteBox">
                        <Grid Opacity="{TemplateBinding Opacity}">
                            <!-- Fix for AutoCompleteBox ContextMenu - Added TemplateBinding between ContextMenu of Textbox inside template and control's ContextMenu  -->
                            <TextBox ContextMenu="{TemplateBinding ContextMenu}" Padding="{TemplateBinding Padding}" Background="{TemplateBinding Background}" IsTabStop="True" x:Name="Text" Style="{TemplateBinding TextBoxStyle}" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" Foreground="{TemplateBinding Foreground}" Margin="0" />
                            <Border x:Name="ValidationErrorElement" Visibility="Collapsed" BorderBrush="#FFDB000C" BorderThickness="1" CornerRadius="1">
                                <ToolTipService.ToolTip>
                                    <ToolTip x:Name="validationTooltip" DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}" Template="{DynamicResource CommonValidationToolTipTemplate}" Placement="Right" PlacementTarget="{Binding RelativeSource={RelativeSource TemplatedParent}}">
                                        <ToolTip.Triggers>
                                            <EventTrigger RoutedEvent="Canvas.Loaded">
                                                <BeginStoryboard>
                                                    <Storyboard>
                                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="validationTooltip" Storyboard.TargetProperty="IsHitTestVisible">
                                                            <DiscreteObjectKeyFrame KeyTime="0">
                                                                <DiscreteObjectKeyFrame.Value>
                                                                    <sys:Boolean>true</sys:Boolean>
                                                                </DiscreteObjectKeyFrame.Value>
                                                            </DiscreteObjectKeyFrame>
                                                        </ObjectAnimationUsingKeyFrames>
                                                    </Storyboard>
                                                </BeginStoryboard>
                                            </EventTrigger>
                                        </ToolTip.Triggers>
                                    </ToolTip>
                                </ToolTipService.ToolTip>
                                <Grid Height="12" HorizontalAlignment="Right" Margin="1,-4,-4,0" VerticalAlignment="Top" Width="12" Background="Transparent">
                                    <Path Fill="#FFDC000C" Margin="1,3,0,0" Data="M 1,0 L6,0 A 2,2 90 0 1 8,2 L8,7 z" />
                                    <Path Fill="#ffffff" Margin="1,3,0,0" Data="M 0,0 L2,0 L 8,6 L8,8" />
                                </Grid>
                            </Border>
                            <Popup x:Name="Popup">
                                <Grid Opacity="{TemplateBinding Opacity}" Background="{TemplateBinding Background}" >
                                    <Border x:Name="PopupBorder" HorizontalAlignment="Stretch" Opacity="0" BorderThickness="0">
                                        <Border.RenderTransform>
                                            <TranslateTransform X="1" Y="1" />
                                        </Border.RenderTransform>
                                        <Border.Background>
                                            <SolidColorBrush Color="#11000000" />
                                        </Border.Background>
                                        <Border HorizontalAlignment="Stretch" Opacity="1.0" Padding="0" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" CornerRadius="0">
                                            <Border.RenderTransform>
                                                <TransformGroup>
                                                    <TranslateTransform X="-1" Y="-1" />
                                                </TransformGroup>
                                            </Border.RenderTransform>
                                            <Border.Background>
                                                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                                    <GradientStop Color="#FFDDDDDD" Offset="0" />
                                                    <GradientStop Color="#AADDDDDD" Offset="1" />
                                                </LinearGradientBrush>
                                            </Border.Background>
                                            <ListBox x:Name="Selector" ScrollViewer.HorizontalScrollBarVisibility="Auto" ScrollViewer.VerticalScrollBarVisibility="Auto" ItemContainerStyle="{TemplateBinding ItemContainerStyle}" Background="{TemplateBinding Background}" Foreground="{TemplateBinding Foreground}" BorderThickness="0" ItemTemplate="{TemplateBinding ItemTemplate}" />
                                        </Border>
                                    </Border>
                                </Grid>
                            </Popup>
                            <vsm:VisualStateManager.VisualStateGroups>
                                <vsm:VisualStateGroup x:Name="PopupStates">
                                    <vsm:VisualStateGroup.Transitions>
                                        <vsm:VisualTransition GeneratedDuration="0:0:0.1" To="PopupOpened" />
                                        <vsm:VisualTransition GeneratedDuration="0:0:0.2" To="PopupClosed" />
                                    </vsm:VisualStateGroup.Transitions>
                                    <vsm:VisualState x:Name="PopupOpened">
                                        <Storyboard>
                                            <DoubleAnimation Storyboard.TargetName="PopupBorder" Storyboard.TargetProperty="Opacity" To="1.0" Duration="0:0:0.1" />
                                        </Storyboard>
                                    </vsm:VisualState>
                                    <vsm:VisualState x:Name="PopupClosed">
                                        <Storyboard>
                                            <DoubleAnimation Storyboard.TargetName="PopupBorder" Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:0.2" />
                                        </Storyboard>
                                    </vsm:VisualState>
                                </vsm:VisualStateGroup>
                                <vsm:VisualStateGroup x:Name="ValidationStates">
                                    <vsm:VisualState x:Name="Valid" />
                                    <vsm:VisualState>
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ValidationErrorElement" Storyboard.TargetProperty="Visibility">
                                                <DiscreteObjectKeyFrame KeyTime="0">
                                                    <DiscreteObjectKeyFrame.Value>
                                                        <Visibility>Visible</Visibility>
                                                    </DiscreteObjectKeyFrame.Value>
                                                </DiscreteObjectKeyFrame>
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </vsm:VisualState>
                                    <vsm:VisualState x:Name="InvalidFocused">
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ValidationErrorElement" Storyboard.TargetProperty="Visibility">
                                                <DiscreteObjectKeyFrame KeyTime="0">
                                                    <DiscreteObjectKeyFrame.Value>
                                                        <Visibility>Visible</Visibility>
                                                    </DiscreteObjectKeyFrame.Value>
                                                </DiscreteObjectKeyFrame>
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="validationTooltip" Storyboard.TargetProperty="IsOpen">
                                                <DiscreteObjectKeyFrame KeyTime="0">
                                                    <DiscreteObjectKeyFrame.Value>
                                                        <sys:Boolean>True</sys:Boolean>
                                                    </DiscreteObjectKeyFrame.Value>
                                                </DiscreteObjectKeyFrame>
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </vsm:VisualState>
                                </vsm:VisualStateGroup>
                            </vsm:VisualStateManager.VisualStateGroups>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Grid.Resources>
    <Grid.RowDefinitions>
        <RowDefinition></RowDefinition>
        <RowDefinition></RowDefinition>
    </Grid.RowDefinitions>
    <toolkit:AutoCompleteBox Style="{DynamicResource AutoCompleteBoxStyle}">
        <toolkit:AutoCompleteBox.ContextMenu>
            <ContextMenu>
                <MenuItem Header="Menu Item 1"></MenuItem>
                <MenuItem Header="Menu Item 2"></MenuItem>
            </ContextMenu>
        </toolkit:AutoCompleteBox.ContextMenu>
    </toolkit:AutoCompleteBox>
    <TextBox Grid.Row="1" >
        <TextBox.ContextMenu>
            <ContextMenu>
                <MenuItem Header="Menu Item 1"></MenuItem>
                <MenuItem Header="Menu Item 2"></MenuItem>
            </ContextMenu>
        </TextBox.ContextMenu>
    </TextBox>
</Grid>

问候, 阿卜杜勒·拉赫曼 A.H.

【讨论】:

    【解决方案2】:

    AutoCompleteBox 公开dependency property TextBoxStyle,您可以set to customize TextBox hosted inside AutoCompleteBox

    另一种方法是提供您自己的模板,我强烈反对,因为此 DP 是为您想要的目的明确提供的,即从外部自定义文本框。

    使用您的自定义 ContextMenu 为 TextBox 创建一个样式,并将该模板应用到您的 TextBox 和 AutoCompleteBox。此示例运行良好 -

    <Grid>
       <Grid.Resources>
          <Style x:Key="CustomStyle" TargetType="TextBox"
                 BasedOn="{StaticResource {x:Type TextBox}}">
             <Setter Property="ContextMenu">
                 <Setter.Value>
                    <ContextMenu>
                        <MenuItem Header="Header1"/>
                        <MenuItem Header="Header2"/>
                     </ContextMenu>
                 </Setter.Value>
             </Setter>
          </Style>
       </Grid.Resources>
       <Grid.RowDefinitions>
          <RowDefinition/>
          <RowDefinition/>
       </Grid.RowDefinitions>
       <toolkit:AutoCompleteBox TextBoxStyle="{StaticResource CustomStyle}"/>
       <TextBox Grid.Row="1" Style="{StaticResource CustomStyle}"/>
    </Grid>
    

    【讨论】:

      猜你喜欢
      • 2020-12-10
      • 2013-06-14
      • 2010-12-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-02
      相关资源
      最近更新 更多