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")