Как видно из кода ниже имя я задаю в конструкторе 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>
Здравствуйте, 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";
Здравствуйте, 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
Здравствуйте, 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";
Здравствуйте, 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. | | | | | | |
| |
Здравствуйте, 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 ?
Здравствуйте, 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.
Здравствуйте, 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 и выше по стеку вызовов.
Так что похоже правильный ответ на исходный вопрос — никак.