1

我正在使用 Silverlight C# 和 XAML 开发 Windows Phone 应用程序。我的页面包含一个ListBox,它呈现用户可以操作的数据绑定对象列表,即添加/重命名/删除。

我已经让项目的添加/重命名就地完成了,即通过根据对象(bool IsEditable属性)的状态将 TextBlock 交换为 TextBox 并使用参数化VisibilityConverter来管理相反的可见性状态。

<UserControl.Resources>
    <local:VisibilityConverter x:Key="VisibilityConverter" True="Visible" False="Collapsed"/>
    <local:VisibilityConverter x:Key="InvertedVisibility" True="Collapsed" False="Visible"/>
</UserControl.Resources>
...
<TextBlock Text="{Binding Name}" Visibility="{Binding IsEditable, Converter={StaticResource InvertedVisibility}}" />
<TextBox Text="{Binding Name}" Visibility="{Binding IsEditable, Converter={StaticResource VisibilityConverter}}"/>

问题是我还希望 TextBox 在可见时自动获取焦点,以便用户无需点击 TextBox 即可弹出屏幕键盘。

由于常规 TextBox 上没有 VisibilityChanged 事件,因此我将 TextBox 子类化为 TextBox2 并添加了我自己的:

public class TextBox2 : TextBox
{
    public TextBox2()
    {
        DefaultStyleKey = typeof(TextBox);
    }

    public static readonly DependencyProperty VisibilityChangedProperty = DependencyProperty.Register(
        "VisibilityChanged",
        typeof(string),
        typeof(TextBox2),
        new PropertyMetadata("Set the VisibilityChanged event handler"));

    public event VisibilityChangedEventHandler VisibilityChanged;

    public delegate void VisibilityChangedEventHandler(object sender, EventArgs e);

    public new Visibility Visibility
    {
        get
        {
            return base.Visibility;
        }
        set
        {
            if (base.Visibility != value)
            {
                base.Visibility = value;
                VisibilityChanged(this, new EventArgs());
            }
        }
    }
}

现在我的 XAML 看起来像这样:

<TextBlock Text="{Binding Name}" Visibility="{Binding IsEditable, Converter={StaticResource InvertedVisibility}}"/>
<local:TextBox2 Text="{Binding Name}" Visibility="{Binding IsEditable, Converter={StaticResource VisibilityConverter}}" VisibilityChanged="ListEdit_VisibilityChanged"/>

和这样的事件处理程序:

void ListEdit_VisibilityChanged(object sender, EventArgs e)
{
    TextBox textBox = (TextBox)sender;
    if (textBox.Visibility == System.Windows.Visibility.Collapsed)
        return;
    textBox.Focus();
}

TextBox2 正确呈现并且在运行时的行为就像 TextBox 一样,但是当数据绑定翻转IsEditable.

IsEditable定义了可见性并且 TextBox2 确实变得正确可见,因此数据绑定正在工作。

我可以通过获取 TextBox2 实例并在代码中设置它的可见性来以编程方式触发事件。这也有效。

但是这个负责设置可见性的数据绑定方案似乎不起作用。

有什么想法为什么不呢?

4

2 回答 2

2

这是我使用的 2 个解决方案。

解决方案 1 不需要子类,但解决方案 2 更可重用。

1 . 您可以订阅 的Loaded事件TextBox,并强制获得焦点,如下所示:

    void TextBox_Loaded_Focus(object sender, System.Windows.RoutedEventArgs e) {
        ForceFocusControl((Control)sender);            
    }

    void ForceFocusControl(Control control) {

        control.Focus();

        if (FocusManager.GetFocusedElement() != control) {

            Dispatcher.BeginInvoke(() => ForceFocusControl(control));
        }
    }

尽管此解决方案进入递归循环,但您可能需要添加一些检查以使其更安全。

2 . 保留您的 subclass TextBox2,而是创建一个MyVisibility绑定到基类属性的私有依赖属性Visibility,但还要指定一个 DependencyProperty_Changed 处理程序,如下所示:

    /// <summary>
    /// <see cref="TextBox2"/> will focus itself when it becomes visible.
    /// </summary>
    public sealed class TextBox2 : TextBox {

        public TextBox2() {

            SetBinding(TextBox2.MyVisibilityProperty, new Binding("Visibility") { Source = this });
        }

        static readonly DependencyProperty MyVisibilityProperty = DependencyProperty.Register(
            /* name = */ "MyVisibilityProperty",
            /* property type = */ typeof(Visibility),
            /* owner type = */ typeof(TextBox2),
            /* meta = */ new PropertyMetadata(MyVisibilityProperty_Changed));

        static void MyVisibilityProperty_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e) {

            TextBox2 TextBox2 = (TextBox2)d;

            if (TextBox2.Visibility == Visibility.Visible) {
                TextBox2.Focus();
            }
        }
    }
于 2013-01-12T14:09:09.020 回答
0

这就是我的 TextBox2 类现在的样子:

public class TextBox2 : TextBox
{
    public event VisibilityChangedEventHandler VisibilityChanged;
    public delegate void VisibilityChangedEventHandler(object sender, EventArgs e);
    public static readonly DependencyProperty VisibilityChangedProperty = DependencyProperty.Register(
        "VisibilityChanged", typeof(VisibilityChangedEventHandler), typeof(TextBox2), null);

    static readonly DependencyProperty MirrorVisibilityProperty = DependencyProperty.Register(
        "MirrorVisibility", typeof(Visibility), typeof(TextBox2), new PropertyMetadata(MirrorVisibilityChanged));

    public TextBox2()
    {
        SetBinding(TextBox2.MirrorVisibilityProperty, new Binding("Visibility") { Source = this });
    }

    static void MirrorVisibilityChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        ((TextBox2)obj).VisibilityChanged(obj, null); // raise event
    }
}
于 2013-01-19T12:32:58.063 回答