Template.FindName не работает если Name задать в коде:
От: Jack128  
Дата: 15.02.19 09:22
Оценка:
Как видно из кода ниже имя я задаю в конструкторе MyScrollViewer, потом использую этот MyScrollViewer в ControlTemplat'e, но FindName возвращает null. Конструктор MyScrollViewer'а вызывается, Name нормально выставляет, а результата — нет.

Если задать Name в XAML'е код работает. Но мне нужно из C# кода.

    public class MyScrollViewer: ScrollViewer
    {
        public MyScrollViewer()
        {
            Name = "PART_ContentHost";
        }
    }
    public class MyTextBox: TextBox
    {
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            var contentHost = Template.FindName("PART_ContentHost", this);
            if (contentHost == null)
                throw new Exception("Can not find PART_ContentHost");
        }
    }



<Window x:Class="WpfApp1.MainWindow"
        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:local="clr-namespace:WpfApp1"        
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Grid.Resources>
            <ControlTemplate TargetType="local:MyTextBox" x:Key="TextBoxTemplate">
                <local:MyScrollViewer />
            </ControlTemplate>
        </Grid.Resources>
        <local:MyTextBox Template="{StaticResource TextBoxTemplate}" />
    </Grid>
</Window>
Re: Template.FindName не работает если Name задать в коде:
От: Egorio Россия  
Дата: 15.02.19 11:24
Оценка:
Здравствуйте, Jack128, Вы писали:

J>Как видно из кода ниже имя я задаю в конструкторе MyScrollViewer, потом использую этот MyScrollViewer в ControlTemplat'e, но FindName возвращает null. Конструктор MyScrollViewer'а вызывается, Name нормально выставляет, а результата — нет.


J>Если задать Name в XAML'е код работает. Но мне нужно из C# кода.


J>
J>    public class MyScrollViewer: ScrollViewer
J>    {
J>        public MyScrollViewer()
J>        {
J>            Name = "PART_ContentHost";
J>        }
J>    }
J>    public class MyTextBox: TextBox
J>    {
J>        public override void OnApplyTemplate()
J>        {
J>            base.OnApplyTemplate();
J>            var contentHost = Template.FindName("PART_ContentHost", this);
J>            if (contentHost == null)
J>                throw new Exception("Can not find PART_ContentHost");
J>        }
J>    }
J>



J>
J><Window x:Class="WpfApp1.MainWindow"
J>        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
J>        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
J>        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
J>        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
J>        xmlns:local="clr-namespace:WpfApp1"        
J>        mc:Ignorable="d"
J>        Title="MainWindow" Height="450" Width="800">
J>    <Grid>
J>        <Grid.Resources>
J>            <ControlTemplate TargetType="local:MyTextBox" x:Key="TextBoxTemplate">
J>                <local:MyScrollViewer />
J>            </ControlTemplate>
J>        </Grid.Resources>
J>        <local:MyTextBox Template="{StaticResource TextBoxTemplate}" />
J>    </Grid>
J></Window>
J>


Здесь https://docs.microsoft.com/ru-ru/dotnet/api/system.windows.frameworkelement.name?view=netframework-4.7.2#System_Windows_FrameworkElement_Name

пишут так:

MyScrollViewer.Name = "PART_ContentHost";
Re[2]: Template.FindName не работает если Name задать в коде:
От: Jack128  
Дата: 15.02.19 13:17
Оценка:
Здравствуйте, Egorio, Вы писали:

J>>[/code]


E>Здесь https://docs.microsoft.com/ru-ru/dotnet/api/system.windows.frameworkelement.name?view=netframework-4.7.2#System_Windows_FrameworkElement_Name


E>пишут так:


E>MyScrollViewer.Name = "PART_ContentHost";


Ну дык я так и делаю. В конструкторе MyScrollViewer
Re[3]: Template.FindName не работает если Name задать в коде:
От: Egorio Россия  
Дата: 15.02.19 13:30
Оценка:
Здравствуйте, Jack128, Вы писали:

J>Здравствуйте, Egorio, Вы писали:


J>>>[/code]


E>>Здесь https://docs.microsoft.com/ru-ru/dotnet/api/system.windows.frameworkelement.name?view=netframework-4.7.2#System_Windows_FrameworkElement_Name


E>>пишут так:


E>>MyScrollViewer.Name = "PART_ContentHost";


J>Ну дык я так и делаю. В конструкторе MyScrollViewer


В конструкторе надо писать this.Name = "PART_ContentHost";
Re[3]: Template.FindName не работает если Name задать в коде:
От: karbofos42 Россия  
Дата: 15.02.19 15:06
Оценка:
Здравствуйте, Jack128, Вы писали:

J>Здравствуйте, Egorio, Вы писали:


J>>>[/code]


E>>Здесь https://docs.microsoft.com/ru-ru/dotnet/api/system.windows.frameworkelement.name?view=netframework-4.7.2#System_Windows_FrameworkElement_Name


E>>пишут так:


E>>MyScrollViewer.Name = "PART_ContentHost";


J>Ну дык я так и делаю. В конструкторе MyScrollViewer


RegisterName
https://docs.microsoft.com/ru-ru/dotnet/api/system.windows.frameworkelement.registername?view=netframework-4.7.2
Re: Template.FindName не работает если Name задать в коде:
От: Sinatr Германия  
Дата: 15.02.19 15:32
Оценка:
Здравствуйте, Jack128, Вы писали:

J>Конструктор MyScrollViewer'а вызывается, Name нормально выставляет, а результата — нет.


Непонятно, чего вы ожидаете. Почитайте про разницу x:Name vs Name, надеюсь догадаетесь сами в чем проблема.
  Подсказка
Что будет если вы в одном ControlTemplate используете 2 MyScrollViewer?
  Еще
Хорошо, в xaml x:Name определяет имя поля в генериуемом коде, что должно случится, когда вы создадите 2 экземпляра MyScrollViewer?
  Я все равно не понял
Имя поля, которое вы ищите в control template, задается в xaml. Просто напишите
    <local:MyScrollViewer x:Name="PART_ControlHost" />
Если вы хотите генерировать control template в коде, динамически, то это возможно, но несколько сложнее, используя FrameworkElementFactory.
---
ПроГLамеры объединяйтесь..
Re: Template.FindName не работает если Name задать в коде:
От: Egorio Россия  
Дата: 15.02.19 15:32
Оценка:
Здравствуйте, Jack128, Вы писали:

J>Как видно из кода ниже имя я задаю в конструкторе MyScrollViewer, потом использую этот MyScrollViewer в ControlTemplat'e, но FindName возвращает null. Конструктор MyScrollViewer'а вызывается, Name нормально выставляет, а результата — нет.


J>Если задать Name в XAML'е код работает. Но мне нужно из C# кода.


J>
J>    public class MyScrollViewer: ScrollViewer
J>    {
J>        public MyScrollViewer()
J>        {
J>            Name = "PART_ContentHost";
J>        }
J>    }
J>    public class MyTextBox: TextBox
J>    {
J>        public override void OnApplyTemplate()
J>        {
J>            base.OnApplyTemplate();
J>            var contentHost = Template.FindName("PART_ContentHost", this);
J>            if (contentHost == null)
J>                throw new Exception("Can not find PART_ContentHost");
J>        }
J>    }
J>


Зачем переопределять станд. класс ScrollViewer ?
Re[2]: Template.FindName не работает если Name задать в коде:
От: Jack128  
Дата: 16.02.19 12:41
Оценка:
Здравствуйте, Sinatr, Вы писали:

S>Если вы хотите генерировать control template в коде, динамически, то это возможно, но несколько сложнее, используя FrameworkElementFactory.


Да, хочу. Но FrameworkElementFactory — deprecated и глючит.

This class is a deprecated way to programmatically create templates, which are subclasses of FrameworkTemplate such as ControlTemplate or DataTemplate; not all of the template functionality is available when you create a template using this class. The recommended way to programmatically create a template is to load XAML from a string or a memory stream using the Load method of the XamlReader class.

Re[4]: Template.FindName не работает если Name задать в коде:
От: Jack128  
Дата: 16.02.19 15:39
Оценка:
Здравствуйте, karbofos42, Вы писали:

K>RegisterName

K>https://docs.microsoft.com/ru-ru/dotnet/api/system.windows.frameworkelement.registername?view=netframework-4.7.2

Это была отличная попытка, но увы. FrameworkTemplate реализует INameScope , позволяет регистрировать у себя имена, но метод FindName(name, templatedParent) не имеет к этому никакого отношения. Этот метод берет имена из свойств FrameworkTemplate.ChildIndexFromChildName/ChildNames. А они заполняются только при проигрывании xaml. Кому интересно -> см TemplateContent.UpdateSharedPropertyNames и выше по стеку вызовов.

Так что похоже правильный ответ на исходный вопрос — никак.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.