我正在为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始终为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。处理程序似乎只对调试有用。我无法看到需要让财产发挥作用。
答案 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
祝你好运!