x: имя не работает, если элемент обернут в содержимое UserControl (Silverlight) - PullRequest
5 голосов
/ 15 июня 2011

Ситуация:

У меня есть "панель-обертка" UserControl, подобная этой (пространства имен и визуальные детали для краткости удалены:)

<UserControl ...>
<Grid x:Name="LayoutRoot" Background="White">
    <ContentPresenter x:Name="integratedPanelContent" Margin="5" /> 
</Grid>
</UserControl>

Затем вКодовый код Я зарегистрировал свойство зависимости

public FrameworkElement PanelContent
{
    get { return (FrameworkElement)GetValue(PanelContentProperty); }
    set { SetValue(PanelContentProperty, value); }
}
public static readonly DependencyProperty PanelContentProperty =
    DependencyProperty.Register("PanelContent", typeof(FrameworkElement), typeof(MyWrapperPanel),
      new PropertyMetadata(null, OnPanelContentChanged));

private static void OnPanelContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    ((MyWrapperPanel)d).OnSetContentChanged(e);
}

protected virtual void OnSetContentChanged(DependencyPropertyChangedEventArgs e)
{
    if (PanelContent != null)
        integratedPanelContent.Content = PanelContent;
}

Теперь я могу обернуть любой контент в свой элемент управления:

<my:MyWrapperPanel x:Name="myWrap">
    <my:MyWrapperPanel.PanelContent>
        <TextBlock x:Name="tbxNothing" Text="Nothing" />
    </my:MyWrapperPanel.PanelContent>
</my:MyWrapperPanel>

Описание проблемы:

Всякий раз, когда я пытаюсь использовать ссылку tbxNothing в codebehind, система выдает NullReferenceException, поскольку tbxNothing, хотя и как ссылка существует, не указывает на TextBlock, определенный в XAML, но имеет значение null.

Возможный (но неудобный) обходной путь:

Существует обходной путь, при котором я удаляю x:Name из TextBlock, а затем я явно определяю частный TextBlock с именем tbxNothing.Затем в обработчике событий OnNavigatedTo я присваиваю значение следующим образом:

tbxNothing = myWrap.PanelContent as TextBlock;

Это работает, но это неправильный способ сделать это, потому что, если контент является панелью стека, которая содержит требуемые элементы управления, яПришлось бы пройтись по дереву, чтобы найти то, что мне нужно, что крайне неудобно.

Вопрос:

Почему текстовый блок больше не виден при переносе в пользовательский элемент управления (описанный способ) и как получить его по его x: Name вкода позади?

1 Ответ

6 голосов
/ 15 июня 2011

Проблема в том, что содержимое вашей панели падает между двумя табуретами.С одной стороны, контент с именем «tbxNothing» создается в области имен главной страницы.Однако в этот момент он не добавляется в дерево объектов.С другой стороны, MyWrapperPanel, являющийся UserControl, имеет свою собственную область имен и в дерево объектов под ним добавляется элемент с именем «tbxNothing».FindName на главной странице не найдет ничего внутри MyWrapperPanel, потому что у него есть собственная область имен, а FindName на MyWrapperPanel не найдет "tbxNothing", потому что он не существует в своей области имен (фактически создаетсяглавная страница).

Ответ - не используйте UserControl в качестве основы для MyWrapperPanel.Вместо этого создайте шаблон управления Silverlight.Измените базовый класс, от которого он наследуется, до ContentControl и настройте его шаблон по умолчанию, добавив ContentPresenter.Должно выглядеть примерно так: -

public class MyWrapperPanel : ContentControl
{
    public MyWrapperPanel ()
    {
        this.DefaultStyleKey = typeof(MyWrapperPanel );
    }
}

, тогда в themes / generic.xaml стиль может выглядеть следующим образом: -

<Style TargetType="local:MyWrapperPanel">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local:MyWrapperPanel">
                <Grid>
                    <ContentPresenter />
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Ваша главная страница xaml будет выглядеть так: -

<my:MyWrapperPanel x:Name="myWrap">
    <TextBlock x:Name="tbxNothing" Text="Nothing" />
</my:MyWrapperPanel>

Обратите внимание, что вывод из ContentControl дает вам свойство Content, к которому автоматически подключается ContentPresenter.

...