WPF - FindName Возвращает ноль, когда это не должно - PullRequest
31 голосов
/ 18 февраля 2010

FindName для меня сломан: (

Если вы являетесь экспертом в таких вещах, я бы хотел помочь.

Объект, который я ищу, есть. У меня есть доказательства.

Вот сценарий:

ToggleButton button = (ToggleButton)sender;
Popup popup = (Popup)button.FindName("popSelectIteration");

popup имеет значение null, но не всегда. Просто иногда. Но даже если для него задано значение null, ребенок, которого я ищу, присутствует.

Я поставил точку останова, когда он был нулевым, и взял эти два снимка экрана.

Здесь FindName возвращает ноль для "popSelectIteration":

альтернативный текст http://img175.imageshack.us/img175/2055/popupisnull.png

Но если вы покопаетесь в часах, то увидите, что там есть ребенок:

альтернативный текст http://img708.imageshack.us/img708/8757/watchwithpopupnull.png

Так чего мне не хватает? Почему FindName не находит его? Как вы можете видеть на снимке экрана, это не проблема синхронизации (часы FindName имеют нулевое значение, но прямой путь в порядке).

Есть ли лучший способ найти элемент управления?

Боковое примечание: Если вы указали в XAML соответствующую кнопку переключения, ее можно найти вs вопрос: WPF - FrameworkElement - Перечислить всех потомков? .


Обновление : я кое-что копал, чтобы понять, почему это иногда терпит неудачу, а иногда -работает.У меня есть анимация, которая вызывает NameScope.SetNameScope((DependencyObject)form, new NameScope()); (полный код метода здесь ).Сразу после этого вызова FindName начинает давать сбой.

Я не совсем понимаю этот вызов.Я думаю, что я скопировал и вставил код.Во всяком случае, я закомментировал это.Но я бы хотел знать, почему это не удается.

Ответы [ 6 ]

35 голосов
/ 18 февраля 2010

Я думаю, это связано с различием между визуальным и логическим деревом.Элемент управления находится в логическом дереве, но, возможно, шаблон для этого элемента управления еще не применен, и поэтому FindName не вернет ничего полезного.

Вы можете попробовать вызвать ApplyTemplate ();сначала на контейнере.

Это также объясняет, почему он иногда что-то возвращает.

33 голосов
/ 02 декабря 2010

Попробуйте

LogicalTreeHelper.FindLogicalNode(button, "popSelectIteration");
6 голосов
/ 07 апреля 2014

По моему опыту, это происходит, когда вы добавляете элементы с помощью кода. Я обнаружил, что вы можете обмануть FindName() (или инфраструктуру анимации) через области имен. То есть, когда вы создаете свой контроль, вы делаете

    NameScope.GetNameScope(yourContainer).RegisterName("name of your control", yourControlInstance);

Для того, чтобы это работало надежно, вы должны убедиться, что вы отменили регистрацию имени:

    NameScope.GetNameScope(yourContainer).UnregisterName("name of your control");

Публикация для дальнейшего использования.

2 голосов
/ 25 октября 2013

У меня сейчас тот же вопрос, но я использую метод, описанный ниже:

    #region Override - OnApplyTemplate

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();

        this.PART_ListViewLeft      = GetTemplateChild(cPART_ListViewLeft)      as ListView;
        this.PART_ListViewCenter    = GetTemplateChild(cPART_ListViewCenter)    as ListView;
        this.PART_ListViewRight     = GetTemplateChild(cPART_ListViewRight)     as ListView;

        this.PART_GridViewLeft      = GetTemplateChild(cPART_GridViewLeft)      as DsxGridView;
        this.PART_GridViewCenter    = GetTemplateChild(cPART_GridViewCenter)    as DsxGridView;
        this.PART_GridViewRight     = GetTemplateChild(cPART_GridViewRight)     as DsxGridView;
        if(this.PART_ListViewLeft!=null)
            this.PART_ListViewLeft      .AlternationCount = this.AlternatingRowBrushes.Count;
        if(this.PART_ListViewCenter!=null)
            this.PART_ListViewCenter    .AlternationCount = this.AlternatingRowBrushes.Count;
        if(this.PART_ListViewRight!=null)
            this.PART_ListViewRight     .AlternationCount = this.AlternatingRowBrushes.Count;
      //  ApplyTempleted = true;
        CreateColumnLayout();
    }
    #endregion

если элемент управления создается динамически, и для какого или чей контейнера для параметра «Видимость» задано скрытие или свертывание, то код «this.PART_ListViewLeft = GetTemplateChild (cPART_ListViewLeft) as ListView;» всегда будет возвращать ноль, причина очевидна: шаблон данных еще не применен до вызова OnApplyTemplate !!!!!!! так что ваш вопрос должен быть таким же !! удачи!

1 голос
/ 18 февраля 2010

Я бы рекомендовал избегать использования функции FindName, исходя из моего опыта, особенно проблематичной, когда вы пытаетесь найти что-то в DataTemplate, примененное к некоторому элементу управления. Вместо этого, если это возможно (в зависимости от архитектуры программного обеспечения), объявите Popup в XAML и обратитесь к нему как к ресурсу или используйте Binding, чтобы установить какое-либо свойство Model в качестве ссылки. Удачи.

0 голосов
/ 03 апреля 2013

Попробуйте использовать button.FindResource("popSelectIteration")

...