Именованные элементы управления внутри свойства содержимого UserControl всегда отображаются нулевыми во время выполнения - PullRequest
7 голосов
/ 15 апреля 2011

Я создал пользовательский элемент управления, который я использую для разных целей.Я определил свойство зависимости, которое содержит UIElement, которое я представляю как содержимое одной из областей пользовательского элемента управления.

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

MyContainer.xaml:

<UserControl x:Class="BSSApp.UI.Tests.MyContainer" x:Name="userControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">

    <Border x:Name="LayoutRoot" Background="Green" CornerRadius="20" BorderBrush="#005500" BorderThickness="10">
        <ContentPresenter Content="{Binding ElementName=userControl, Path=MyContent}" Margin="20"/>

    </Border>
</UserControl>

MyContainer.xaml.cs

namespace BSSApp.UI.Tests
{
    public partial class MyContainer : UserControl
    {
        public static readonly DependencyProperty MyContentProperty =
                    DependencyProperty.Register("MyContent",
                                                typeof(UIElement),
                                                typeof(MyContainer),
                                                new PropertyMetadata(new Grid()));

        public UIElement MyContent
        {
            get
            {
                return (UIElement)GetValue(MyContentProperty);
            }
            set
            {
                SetValue(MyContentProperty, value);
            }
        }


        public MyContainer()
        {
            InitializeComponent();
        }
    }
}

И класс использования: UserControlContentBug.xaml:

<UserControl x:Class="BSSApp.UI.Tests.UserControlContentBug"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:t="clr-namespace:BSSApp.UI.Tests"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">

    <Grid x:Name="LayoutRoot" Background="White">
        <t:MyContainer>
            <t:MyContainer.MyContent>
                <Button Name="btnWithName" Click="btnWithName_Click">Click Me</Button>
            </t:MyContainer.MyContent>
        </t:MyContainer>
    </Grid>
</UserControl>

и код позади: UserControlContentBug.xaml.cs

 namespace BSSApp.UI.Tests
 {
     public partial class UserControlContentBug : UserControl
     {
         public UserControlContentBug()
         {
             InitializeComponent();
         }

         private void btnWithName_Click(object sender, RoutedEventArgs e)
         {
             // this throws an exception
             btnWithName.Tag=2;
         }
     }
  }

Итак, есть объявление кнопки с именем"btnWithName".переменная действительно объявлена ​​в коде, но она имеет значение null ... Это происходит только тогда, когда кнопка объявлена ​​внутри свойства другого пользовательского элемента управления.

Кто-нибудь знает, как решить эту проблему?

Спасибо

Ответы [ 2 ]

6 голосов
/ 18 мая 2011

Я сам столкнулся с этой проблемой.Сгенерированный частичный класс (например, obj \ UserControlContentBug.xaml.g.cs), который определяет именованные элементы, доступные для кода в вашем XAML, использует FrameworkElement.FindName () для выполнения этих назначений.

Согласно MSDN:

API времени выполнения, такой как FindName, работает с деревом объектов.Эти объекты загружаются в область содержимого и механизм выполнения CLR всего подключаемого модуля Silverlight.Когда часть дерева объектов создается из шаблонов или загруженного XAML во время выполнения, область имен XAML обычно не является смежной со всем этим деревом объектов.В результате в дереве объектов может быть именованный объект, который не может найти данный вызов FindName.

Поскольку MyContainer устанавливает свою собственную границу именной области как UserControl, вызов FindName () из UserControlContentBug не будетисследовать эту часть дерева объектов (где определено btnWithName).

Вероятно, есть несколько способов обойти это, но самый простой способ, который мне подходит, это:

  1. Дайте MyContainer имя (x:Name="myContainer").

  2. Удалите имя из Button (btnWithName), чтобы лишняя переменная с постоянным нулевым значением с тем же именемНе зарезервировано в сгенерированном коде C #.

  3. Создать ссылку на кнопку в коде позади.

Примерно так:

namespace BSSApp.UI.Tests
{
    public partial class UserControlContentBug : UserControl
    {
        private Button btnWithName;

        public UserControlContentBug()
        {
            Loaded += UserControlContentBugLoaded;
            InitializeComponent();
        }

        private void UserControlContentBugLoaded(object sender, System.Windows.RoutedEventArgs e)
        {
            btnWithName = myContainer.MyContent as Button;
        }

        private void btnWithName_Click(object sender, RoutedEventArgs e)
        {
            // this throws an exception, not so much
            btnWithName.Tag=2;
        }
    }
}

Надеюсь, это поможет.

0 голосов
/ 15 апреля 2011

Попробуйте использовать x: Name вместо Name на кнопке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...