小侃 發表於 2025-7-19 20:47:00

TextBoxPopupBehavior控件

<h2 id="功能说明">功能说明</h2>
<p>一个用于 WPF TextBox 的附加行为,实现 TextBox 与 Popup 控件的联动效果:</p>
<ol>
<li>
<p><strong>自动弹出/关闭</strong>:</p>
<ul>
<li>TextBox 获得焦点时自动打开关联的 Popup</li>
<li>TextBox 失去焦点时自动关闭关联的 Popup</li>
</ul>
</li>
<li>
<p><strong>点击外部关闭</strong>:</p>
<ul>
<li>点击 TextBox 和 Popup 外部区域时关闭 Popup</li>
</ul>
</li>
<li>
<p><strong>焦点状态处理</strong>:</p>
<ul>
<li>解决 TextBox 保持焦点但 Popup 关闭后的重新触发问题</li>
</ul>
</li>
</ol>
<h2 id="核心代码解析">核心代码解析</h2>
<pre><code class="language-csharp">      // 解决在 TextBox 外其他地方点击时,仅关闭 Popup,但是 TextBox 还是 Focused 状态,导致再点击进来时不会触发弹出 Popup
      private void AssociatedObject_PreviewMouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e) {
            if (AssociatedObject?.IsFocused == true &amp;&amp; Popup != null &amp;&amp; !Popup.IsOpen) {
                Popup.IsOpen = true;
            }
      }

      private void Window_PreviewMouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e) {
            if (Popup == null || !Popup.IsOpen || AssociatedObject == null || _parentWindow == null) { return; }

            Point position = e.GetPosition(null);
            Rect textBoxRect = new Rect(AssociatedObject.TranslatePoint(new Point(0, 0), _parentWindow), AssociatedObject.RenderSize);
            Rect popupRect = new Rect(Popup.TranslatePoint(new Point(0, 0), _parentWindow), Popup.RenderSize);
            if (!textBoxRect.Contains(position) &amp;&amp; !popupRect.Contains(position)) {
                Popup.SetCurrentValue(Popup.IsOpenProperty, false);
            }
      }
</code></pre>
<h2 id="使用方法">使用方法</h2>
<pre><code class="language-xml">&lt;TextBox x:Name="SearchBox"
         Width="400"
         Height="30"
         Text="{Binding ElementName=list, Path=SelectedItem.Content}"&gt;
    &lt;hc:Interaction.Behaviors&gt;
      &lt;controls:TextBoxPopupBehavior Popup="{Binding ElementName=SuggestionsPopup}" /&gt;
    &lt;/hc:Interaction.Behaviors&gt;
&lt;/TextBox&gt;

&lt;Popup x:Name="SuggestionsPopup"
       Placement="Bottom"
       PlacementTarget="{Binding ElementName=SearchBox}"
       StaysOpen="True"&gt;
    &lt;Border Background="White"
            BorderBrush="Gray"
            BorderThickness="1"&gt;
      &lt;ListBox x:Name="list"
               Width="200"
               Height="150"&gt;
            &lt;ListBoxItem&gt;选项1&lt;/ListBoxItem&gt;
            &lt;ListBoxItem&gt;选项2&lt;/ListBoxItem&gt;
            &lt;ListBoxItem&gt;选项3&lt;/ListBoxItem&gt;
      &lt;/ListBox&gt;
    &lt;/Border&gt;
&lt;/Popup&gt;
</code></pre>
<h2 id="注意事项">注意事项</h2>
<ul>
<li>确保 Popup 的 PlacementTarget 正确绑定</li>
<li>在 MVVM 模式下可通过绑定设置 Popup 属性</li>
<li>控件卸载时会自动清理事件监听</li>
</ul>


</div>
<div id="MySignature" role="contentinfo">
    <div>
        <hr style="height: 2px; border: none; border-top: 2px groove skyblue">
</div>

<div style="text-align: center">
<img src="https://img2024.cnblogs.com/blog/335284/202604/335284-20260402200630931-853910823.jpg"><br>
<span>欢迎您扫一扫上面的微信公众号, 订阅我的博客!</span><br><br>
</div>

<div>
<strong>文章作者:</strong><span style="line-height: 1.5">Memento</span><br>
<strong>博客地址:</strong><span style="color: #337FE5">http://www.cnblogs.com/Memento/</span><br>
<strong>版权声明:</strong><span style="line-height: 1.5">Memento所有文章遵循</span><span style="color: #337FE5">创作共用版权协议</span><span style="line-height: 1.5">,要求</span><strong>署名、非商业、保持一致</strong><span style="line-height: 1.5">。在满足</span><span style="color: #337FE5">创作共用版权协议</span><span style="line-height: 1.5">的基础上可以转载,但请以超链接形式注明出处。</span>
</div>
<div>
        <hr style="height: 2px; border: none; border-top: 2px groove skyblue">
</div><br><br>
来源:https://www.cnblogs.com/memento/p/18993294
頁: [1]
查看完整版本: TextBoxPopupBehavior控件