关闭包含 UserControl 的 Flyout

Close Flyout which contains a UserControl

我正在为 TextBox 构建用户控件,因为我希望它有一些特殊的行为。

该控件可以在多种上下文中使用,包括作为按钮的弹出按钮。当它是弹出窗口时,我想在用户在编辑文本时按下 Enter 键时关闭弹出窗口。

为实现这一点,该控件有一个 ParentButton 依赖项 属性,如果设置了该依赖项,则会将按钮与弹出按钮一起存储,父页面的 XAML 将其设置在这个案例。该控件有一个 KeyUp 处理程序,它检测 Enter 键,如果设置了 ParentButton 属性,则关闭其弹出窗口。

TextBoxUC.xaml

<UserControl
x:Class="TextBoxUCDemo.TextBoxUC"
...
xmlns:local="using:TextBoxUCDemo"
...>

<StackPanel Width="250">
    <TextBox KeyUp="TextBox_KeyUp" Text="Hello" />
</StackPanel>

TextBoxUC.xaml.cs

    public sealed partial class TextBoxUC : UserControl
{
    public TextBoxUC() {
        this.InitializeComponent();
    }

    internal static readonly DependencyProperty ParentButtonProperty =
      DependencyProperty.Register("ParentButton", typeof(Button), typeof(TextBoxUC), new PropertyMetadata(null));

    public Button ParentButton {
        get { return ((Button)GetValue(ParentButtonProperty)); }
        set { SetValue(ParentButtonProperty, value); }
    }

    private void TextBox_KeyUp(object sender, KeyRoutedEventArgs e) {

        switch (e.Key) {
            case VirtualKey.Enter:

                // (Do something with the Text...)

                // If this is a flyout from a button then hide the flyout.
                if (ParentButton != null) { // Always null!
                    ParentButton.Flyout.Hide();
                }

                break;
            default: return;
        }

    }

}

MainPage.xaml

<Page
x:Class="TextBoxUCDemo.MainPage"
...
xmlns:local="using:TextBoxUCDemo"
...>

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" Margin="200,300">
    <Button Name="flyoutTextBoxButton" Content="Edit">
        <Button.Flyout>
            <Flyout>
                <local:TextBoxUC ParentButton="{Binding ElementName=flyoutTextBoxButton, Path=.}"/>
            </Flyout>
        </Button.Flyout>
    </Button>

</Grid>

问题是 ParentButton 始终为空。

-- 编辑--

我已将问题缩小到绑定到 XAML 中的元素。如果我从 MainPage 的代码隐藏中设置 ParentButton,那么它就可以工作。

在'MainPage.xaml'中:

Loaded="Page_Loaded"
....
<local:TextBoxUC/>

MainPage.xaml.cs

private void Page_Loaded(object sender, RoutedEventArgs e) {
    textBoxUC.ParentButton = this.flyoutTextBoxButton;
}

效果:

                    if (ParentButton != null) { 
                       // Reaches here
                }

所以:问题出在xaml ParentButton="{Binding ElementName=flyoutTextBoxButton, Path=.}",它编译但没有效果。

如果我将更改的事件处理程序添加到依赖项 属性 的注册中,则当从代码隐藏设置 ParentButton 时会调用该处理程序,但不会调用绑定到 ElementName。处理程序似乎只对调试有用。我看不出 属性 工作需要它。

您正在将其作为依赖项 属性。这是第一个正确的开始。但在您处理更改的事件之前,您不会真正从中获得任何价值。

我在这里讨论更多:

http://blog.jerrynixon.com/2013/07/solved-two-way-binding-inside-user.html

祝你好运!

您可以将包含 lambda 表达式的 Action 类型的法线 属性 添加到控件中。 您将在创建控件时设置此 属性,然后在 EnterPressed 事件上在您的控件内调用它。

public class MyControll
{
  public Action ActionAfterEnterPressed {get; set;}

  private void HandleOnEnterPressed()
  {
   if(ActionAfterEnterPressed != null)
   {
     ActionAfterEnterPressed.Invoke();
   }
  }
}

创建控件的地方

...
MyControl c = new MyControl()
c.ActionAfterEnterPressed = CloseFlyuot;
....
private void CloseFlyuot()
{
  _myFlyout.IsOpen = false;
}

通过这种方式,您可以设置任何操作并在需要时从您的控件内部调用它,而无需理会操作实际执行的操作。 祝你好运。

好的,这个怎么样?我过去用过它。工作正常。

[Microsoft.Xaml.Interactivity.TypeConstraint(typeof(Windows.UI.Xaml.Controls.TextBox))]
public class CloseFlyoutOnEnterBehavior : DependencyObject, IBehavior
{
    public DependencyObject AssociatedObject { get; set; }

    public void Attach(DependencyObject obj)
    {
        this.AssociatedObject = obj;
        (obj as TextBox).KeyUp += TextBox_KeyUp;
    }

    void TextBox_KeyUp(object sender, KeyRoutedEventArgs e)

    {
        if (!e.Key.Equals(Windows.System.VirtualKey.Enter))
            return;
        var parent = this.AssociatedObject;
        while (parent != null)
        {
            if (parent is FlyoutPresenter)
            {
                ((parent as FlyoutPresenter).Parent as Popup).IsOpen = false;
                return;
            }
            else
            {
                parent = VisualTreeHelper.GetParent(parent);
            }
        }
    }

    public void Detach()
    {
        (this.AssociatedObject as TextBox).KeyUp -= TextBox_KeyUp;
    }
}

这样使用:

<Button HorizontalAlignment="Center"
        VerticalAlignment="Center"
        Content="Click Me">
    <Button.Flyout>
        <Flyout Placement="Bottom">
            <TextBox Width="200"
                        Header="Name"
                        PlaceholderText="Jerry Nixon">
                <Interactivity:Interaction.Behaviors>
                    <local:CloseFlyoutOnEnterBehavior />
                </Interactivity:Interaction.Behaviors>
            </TextBox>
        </Flyout>
    </Button.Flyout>
</Button>

在此处了解有关行为的更多信息:

http://blog.jerrynixon.com/2013/10/everything-i-know-about-behaviors-in.html

这里(第 3 课):

http://blog.jerrynixon.com/2014/01/the-most-comprehensive-blend-for-visual.html

祝你好运!