【问题标题】:Programatically set focus to control in itemscontrol datatemplate以编程方式将焦点设置为项目控制数据模板中的控制
【发布时间】:2014-01-11 05:18:03
【问题描述】:

我有一个绑定到可观察集合的标题项控件。集合中的项目与数据模板相关联。数据模板非常简单,它只包含两个文本框。我遇到困难的部分是以编程方式将焦点设置到文本框。

第一次显示项目控件时,它总是有一个项目。它可能有也可能没有绑定到第一个文本框的值。如果它有值,则需要将焦点设置到第二个文本框。我使用以下方法完成了此操作:

    protected override void OnActivated(EventArgs e)
    {
        base.OnActivated(e);

        if (_activated) return;

        _activated = true;

        var dc = DataContext as MyViewModel;
        if (null != dc)
        {

            var cp = theItemsControl.ItemContainerGenerator.ContainerFromIndex(0) as ContentPresenter;
            var tb = FindVisualChildren<TextBox>(cp);
            if (tb != null)
            {
                if (!String.IsNullOrEmpty(dc.TheCollection.First().FirstValue))
                {
                    var t = tb.FirstOrDefault(box => box.Name == "SecondTextBox");
                    if (null != t) t.Focus();
                }
                else
                {
                    var t = tb.FirstOrDefault(box => box.Name == "FirstTextBox");
                    if (null != t) t.Focus();
                }
            }
        }
    }

这似乎工作正常。但是,现在,当将新项目添加到集合中时,我需要将焦点设置到 FirstTextBox。我尝试使用 FocusManager 在数据模板中设置焦点,但这会阻止上述代码正常工作。我还在视图中尝试了以下操作。在将新项目添加到 ObservableCollection 后,从 ViewModel 调用该方法。代码运行,但找不到任何文本框(即 tb == null)。此时是否已创建控件?

    public void SetFocusToNewItem(int index)
    {
        var dc = DataContext as MyViewModel;
        if (null != dc)
        {

            var cp = theItemsControl.ItemContainerGenerator.ContainerFromIndex(index) as ContentPresenter;
            var tb = FindVisualChildren<TextBox>(cp);
            if (tb != null)
            {
                  var t = tb.FirstOrDefault(box => box.Name == "FirstTextBox");
                  if (null != t) t.Focus();
            }
        }
    }

添加项目后是否有其他解决方案来设置焦点?

【问题讨论】:

    标签: c# wpf itemscontrol


    【解决方案1】:

    有时以下技巧对我有用:

    // Replace such call:
    SetFocusToNewItem(newIndex);
    
    // By this:
    Dispatcher.BeginInvoke((Action) (() =>
    {
        SetFocusToNewItem(newIndex);
    }));
    

    问题是当您在集合中添加一个项目时,UI 元素未创建,因此您无法获取它。上面的代码会延迟你的函数执行,你的方法应该在创建 UI 之后执行。

    PS:您可以将 Dispatcher 调用移动到您的方法中。

    编辑:

    这也可能有帮助(对我有用):

    var cp = theItemsControl.ItemContainerGenerator.ContainerFromIndex(index) as ContentPresenter;
    cp.Loaded += (s, e2) => 
                {
                    var tb = FindVisualChildren<TextBox>(e2.Source as UIElement)
                             .FirstOrDefault();
                    if (tb != null)
                        tb.Focus();
                };
    

    原因相同:UI元素没有创建。

    【讨论】:

    • 焦点仍然没有移动到文本框。 FindVisualChildren 仍然返回 null。我似乎没有把电话耽搁得够久。更新 UI 时是否会引发任何事件?
    猜你喜欢
    • 1970-01-01
    • 2015-04-26
    • 1970-01-01
    • 2011-10-15
    • 2011-10-19
    • 1970-01-01
    • 1970-01-01
    • 2017-12-22
    • 2011-04-12
    相关资源
    最近更新 更多