关闭包含UserControl的弹出窗口

时间:2015-02-09 00:13:07

标签: windows-runtime windows-store-apps winrt-xaml

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

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

Textbox is presented as flyout, and user presses enter to close the flyout]![enter image description here

为实现此目的,控件具有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始终为null。

- 编辑 -

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

在MainPage.xaml&#39;:

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。处理程序似乎只对调试有用。我无法看到需要让财产发挥作用。

3 个答案:

答案 0 :(得分:6)

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

[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

祝你好运!

答案 1 :(得分:1)

您可以向Action中添加包含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;
}

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

答案 2 :(得分:0)

你正在使它成为依赖属性。这是第一次,正确的开始。但是在你处理改变后的事件之前,你实际上并没有从中获得任何价值。

我在这里讨论更多:

  

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

祝你好运!