WPF - FindName Возвращает ноль, когда это не должно

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

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

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

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

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

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

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

Вот где FindName возвращает значение null для "popSelectIteration":

http://img175.imageshack.us/img175/2055/popupisnull.png

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

http://img708.imageshack.us/img708/8757/watchwithpopupnull.png

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

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

Дополнительное примечание: Если вы включили XAML для рассматриваемой кнопки переключения, это можно найти в следующем вопросе: WPF - FrameworkElement - перечислить всех потомков?,


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

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

6 ответов

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

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

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

Пытаться

LogicalTreeHelper.FindLogicalNode(button, "popSelectIteration");

Немного поздно на вечеринку (и на самом деле не ответ на вопрос OP), но

когда вы добавляете элементы динамически, они не могут быть найдены FindName. Их необходимо зарегистрировать, позвонивRegisterName.

Пример:

Button myButton = new Button();
myButton.Content = generateNumber();
myButton.Name = "button_" + generateNumber;

RegisterName(myButton.Name, myButton);

Panel.Children.Add(myButton);
object o = Panel.FindName(myButton.Name);

Может, кому-то это пригодится.

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

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

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

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

Размещать это для дальнейшего использования.

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

    #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;" всегда будет возвращать null, причина ясна: шаблон данных еще не был применен до вызова OnApplyTemplate!!!!!!! так что ваш вопрос должен быть таким же!! удачи!

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

Ellipse Storyboard.Children.Add(myRectAnimation); containerCanvas.Children.Add(myPath); После добавления зарегистрируйте такие элементы управления, как RegisterName("TextBlock1", Var_TextBox); или RegisterName(myRectAnimation.Name,myRectAnimation); RegisterName(myPath.Name,myPath);

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

Другие вопросы по тегам