以编程方式设置焦点以控制itemscontrol datatemplate

时间:2013-12-23 01:28:05

标签: c# wpf itemscontrol

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

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

    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在datatemplate中设置焦点,但这禁止上述代码正常工作。我也在视图中尝试了以下内容。将新项添加到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();
            }
        }
    }

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

1 个答案:

答案 0 :(得分:0)

有时以下技巧对我有用:

// 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元素。