Добрый день.
Подскажите, пожалуйста, такую вещь:
WPF окно, есть TabControl, в Items этого табконтрола есть два разных объекта, Class1 И Class2. В Ресурсах окна есть два <DataTemplate DataType="{x:Type src:Class1}"> и <DataTemplate DataType="{x:Type src:Class2}">
Таким образом, TabControl сам выбирает подходящий дататемплейт из этих двух.
Проблема. При смене таба в SelectionChanged не получается пощупать примененный к SelectedItem ContentTemplate (выбранный табом из двух DataTemplate).
Аналогично пробовал получить TabItem и из него контент темплейт, но везде null. Пробовал и с ContentTemplateSelector, но там тоже свои причуды.
Хочется получить этот темплейт ПЕРЕД показом другой вкладки, чтобы провести в нем некоторые изменения на лету.
Здравствуйте, lsoft, Вы писали:
L>Проблема. При смене таба в SelectionChanged не получается пощупать примененный к SelectedItem ContentTemplate (выбранный табом из двух DataTemplate). L>Аналогично пробовал получить TabItem и из него контент темплейт, но везде null. Пробовал и с ContentTemplateSelector, но там тоже свои причуды.
Можно попробовать достучаться до темплейтов, используя DataTemplateKey.
DataTemplateKey key = new DataTemplateKey(typeof(Class1));
DataTemplate template = this.FindResource(key) as DataTemplate;
Ищи прямо в ресурсах TabControl'а, они должны видеть все вышележащие.
Re[2]: [WPF] Получение уже примененного DataTemplate у TabCo
От:
Аноним
Дата:
20.02.09 11:18
Оценка:
MxKazan,
спасибо за ответ, но в проекте почти именно так и написано, однако попытка поиска элемента в шаблоне приводит к
"Данная операция допустима только для элементов, к которым применяется этот шаблон."
DataTemplateKey key = new DataTemplateKey(this.tabControl.SelectedItem.GetType());
DataTemplate fooTemplate = this.tabControl.FindResource(key) as DataTemplate;
var contentPresenter = this.tabControl.Template.FindName("PART_SelectedContentHost", this.tabControl) as ContentPresenter; ;
var _def1 = fooTemplate.FindName("def1", contentPresenter);
var _def2 = fooTemplate.FindName("def2", contentPresenter);
Re[3]: [WPF] Получение уже примененного DataTemplate у TabCo
Здравствуйте, Аноним, Вы писали:
А>спасибо за ответ, но в проекте почти именно так и написано, однако попытка поиска элемента в шаблоне приводит к А>"Данная операция допустима только для элементов, к которым применяется этот шаблон."
Что нужно сделать в шаблоне? Может лучше это через какие-нибудь биндинги реализовать?
Re[4]: [WPF] Получение уже примененного DataTemplate у TabCo
Здравствуйте, MxKazan, Вы писали:
MK>Здравствуйте, Аноним, Вы писали:
А>>спасибо за ответ, но в проекте почти именно так и написано, однако попытка поиска элемента в шаблоне приводит к А>>"Данная операция допустима только для элементов, к которым применяется этот шаблон." MK>Что нужно сделать в шаблоне? Может лучше это через какие-нибудь биндинги реализовать?
нужно найти в шаблоне кнопку и модифицировать у нее контекстное меню. на разных вкладках (одного типа) будут разные пункты в контекстном меню. точнее даже не разные, а произвольные.
Re[5]: [WPF] Получение уже примененного DataTemplate у TabCo
Здравствуйте, lsoft, Вы писали:
L>нужно найти в шаблоне кнопку и модифицировать у нее контекстное меню. на разных вкладках (одного типа) будут разные пункты в контекстном меню. точнее даже не разные, а произвольные.
Повесить обработчик на раскрытие контекстное меню и уже в зависимости от кого раскрывается, добавлять нужные menu item'ы.
Re[5]: [WPF] Получение уже примененного DataTemplate у TabCo
Получилось сделать что-то похожее. Если в TabControl.Items добавлять объекты своих классов (Class1,Class2) и предоставить TabControl'у возможность самому искать подходящий шаблон из ресурсов, то таб контрол начинает отображать одинаковое содержимое как в заголовке вкладки, так и в содержимом вкладки.
Мне удалось находить шаблон в ЗАГОЛОВКЕ вкладки и менять его. Привожу код.
Осталось только научиться находить объект шаблона для СОДЕРЖИМОГО вкладки.
var c0 = this.tabControl.ItemContainerGenerator.ContainerFromIndex(0) as TabItem;
c0.GotFocus += new RoutedEventHandler(c0_GotFocus);
var c1 = this.tabControl.ItemContainerGenerator.ContainerFromIndex(1) as TabItem;
c1.GotFocus += new RoutedEventHandler(c0_GotFocus);
var c2 = this.tabControl.ItemContainerGenerator.ContainerFromIndex(2) as TabItem;
c2.GotFocus += new RoutedEventHandler(c0_GotFocus);
tabLoaded = true;
tabLoaded — объявлена в классе окна, основная функция, где все делается:
void c0_GotFocus(object sender, RoutedEventArgs e)
{
DataTemplateKey key = new DataTemplateKey((sender as TabItem).Content.GetType());
DataTemplate fooTemplate = base.FindResource(key) as DataTemplate;
ContentControl contentCtrl = (sender as TabItem) as ContentControl;
var contentPresenter = FindVisualChild<ContentPresenter>(
//this.tabControl);
(sender as TabItem));
//DataTemplateKey key = new DataTemplateKey((sender as TabItem).Content.GetType());
//DataTemplate fooTemplate = this.tabControl.FindResource(key) as DataTemplate;var _def1 = fooTemplate.FindName("def1", contentPresenter);
var _def2 = fooTemplate.FindName("def2", contentPresenter);
if (_def1 != null)
(_def1 as Label).Content = new Random().Next();
if (_def2 != null)
(_def2 as Label).Content = new Random().Next();
}
вспомогательная функция
private childItem FindVisualChild<childItem>(DependencyObject obj)
where childItem : DependencyObject
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
if (child != null && child is childItem)
return (childItem)child;
else
{
childItem childOfChild = FindVisualChild<childItem>(child);
if (childOfChild != null)
return childOfChild;
}
}
return null;
}
Надеюсь, кто-нибудь сделает следущий шаг и научится брать шаблон содержимого вкладки. Я чувствую, что я уже почти пас. Второй день насилую себе мозг.
Re[6]: [WPF] Получение уже примененного DataTemplate у TabCo
Здравствуйте, MxKazan, Вы писали:
MK>Здравствуйте, lsoft, Вы писали:
L>>нужно найти в шаблоне кнопку и модифицировать у нее контекстное меню. на разных вкладках (одного типа) будут разные пункты в контекстном меню. точнее даже не разные, а произвольные. MK>Повесить обработчик на раскрытие контекстное меню и уже в зависимости от кого раскрывается, добавлять нужные menu item'ы.
То, что Вы предлагаете, это понятно. Но это не выход. А если мне захочется создать кнопку, например? Или, программно сдвинуть GridSplitter?
Есть общая задача: научиться получать шаблон контента при переключении таб контрола.
Я думаю, у этой задачи должно быть решение.
Re[7]: [WPF] Получение уже примененного DataTemplate у TabCo
Здравствуйте, lsoft, Вы писали:
L>То, что Вы предлагаете, это понятно. Но это не выход. А если мне захочется создать кнопку, например? Или, программно сдвинуть GridSplitter? L>Есть общая задача: научиться получать шаблон контента при переключении таб контрола. L>Я думаю, у этой задачи должно быть решение.
Эта задача неверная. Если хочется менять шаблон, делайте его программно. Другой вариант делать в XAML некоторую основу визуального дерева и, при переключении вкладок, модифицировать ее и присваивать как ContentTemplate выбранной вкладки.
Re[8]: [WPF] Получение уже примененного DataTemplate у TabCo
Здравствуйте, MxKazan, Вы писали:
MK>Эта задача неверная. Если хочется менять шаблон, делайте его программно. Другой вариант делать в XAML некоторую основу визуального дерева и, при переключении вкладок, модифицировать ее и присваивать как ContentTemplate выбранной вкладки.
Не будем спорить, пусть каждый остается при своем мнении. Если сделать моим способом не получится, разумеется, придется искать другие варианты.
Спасибо за диалог! :)
Re[6]: [WPF] Получение уже примененного DataTemplate у TabCo
Здравствуйте, lsoft, Вы писали:
L>Получилось сделать что-то похожее. Если в TabControl.Items добавлять объекты своих классов (Class1,Class2) и предоставить TabControl'у возможность самому искать подходящий шаблон из ресурсов, то таб контрол начинает отображать одинаковое содержимое как в заголовке вкладки, так и в содержимом вкладки. L>Мне удалось находить шаблон в ЗАГОЛОВКЕ вкладки и менять его. Привожу код. L>Осталось только научиться находить объект шаблона для СОДЕРЖИМОГО вкладки.
Честно говоря, я уже плохо понимаю о чем речь, но прочитав, возникло мнение, что вы запутались с моделью содержимого TabControl. Дело в том, что хоть TabItem и является ContentControl'ом, но фактически ее содержимое светится как содержимое TabControl, в шаблоне которого есть отдельный ContentPresenter. В одном из ваших примеров кода идет поиск в ContentPresenter'е TabItem'а, а надо искать в ContentPresenter'е TabControl'а. Зовется он PART_SelectedContentHost. Также есть свойства SelectedContent*.
Re[7]: [WPF] Получение уже примененного DataTemplate у TabCo
Здравствуйте, MxKazan, Вы писали:
MK>Честно говоря, я уже плохо понимаю о чем речь, но прочитав, возникло мнение, что вы запутались с моделью содержимого TabControl. Дело в том, что хоть TabItem и является ContentControl'ом, но фактически ее содержимое светится как содержимое TabControl, в шаблоне которого есть отдельный ContentPresenter. В одном из ваших примеров кода идет поиск в ContentPresenter'е TabItem'а, а надо искать в ContentPresenter'е TabControl'а. Зовется он PART_SelectedContentHost. Также есть свойства SelectedContent*.
1) да, вероятно, уже запутался :)
2) SelectedContent* все равны нулю, за исключением SelectedContent который содержит мой Class1(2)
3) про PART_SelectedContentHost мне известно:
void c0_GotFocus(object sender, RoutedEventArgs e)
{
DataTemplateKey key = new DataTemplateKey((sender as TabItem).Content.GetType());
DataTemplate fooTemplate = base.FindResource(key) as DataTemplate;
ContentControl contentCtrl = (sender as TabItem) as ContentControl;
var contentPresenter = this.tabControl.Template.FindName(
"PART_SelectedContentHost",
this.tabControl)
as ContentPresenter;
//var contentPresenter = FindVisualChild<ContentPresenter>(
// //this.tabControl);
// (sender as TabItem));var _def1 = fooTemplate.FindName("def1", contentPresenter);
var _def2 = fooTemplate.FindName("def2", contentPresenter);
if (_def1 != null)
(_def1 as Label).Content = new Random().Next();
if (_def2 != null)
(_def2 as Label).Content = new Random().Next();
}
удивительно, но этот код падает с аналогичной ошибкой, но не сразу. удается перейти на вкладку другого типа, но вернуться на первую вкладку не получается — ошибка. в общем, этот код срабатывает только при первом открытии вкладки.
спасибо еще раз за разъяснения.
Re[8]: [WPF] Получение уже примененного DataTemplate у TabCo
Здравствуйте, Vladek, Вы писали:
V>Здравствуйте, lsoft, Вы писали: L>>Хочется получить этот темплейт ПЕРЕД показом другой вкладки, чтобы провести в нем некоторые изменения на лету. V>Чем не угодили DataTrigger-ы?
простите, не понимаю, как DataTrigger мне может помочь в осуществлении моего коварного плана по получению DataTemplate
Re[3]: [WPF] Получение уже примененного DataTemplate у TabCo
Здравствуйте, lsoft, Вы писали:
L>Здравствуйте, Vladek, Вы писали:
V>>Здравствуйте, lsoft, Вы писали: L>>>Хочется получить этот темплейт ПЕРЕД показом другой вкладки, чтобы провести в нем некоторые изменения на лету.
Вообще, такие вещи, как содержимое какого-нить меню, лучше хранить не в темплейте, а в коллекции какой-нить. Тогда у вас сразу эта проблема отпадет.
Re: [WPF] Получение уже примененного DataTemplate у TabContr
Проблема решена, сердечное спасибо всем, кто принял посильное участие.
Суть проблемы была в том, что во время переключения вкладки в ТабКонтроле, не всегда удавалось найти примененный дататемплейт. Иногда удавалось, иногда нет. Как оказалось, это происходило из-за того, что к моменту вызова TabItem.GotFocus к PART_SelectedContentHost НЕ ВСЕГДА применялся новый ДатаТемплейт.
в результате работает примерно следующее:
void c0_GotFocus(object sender, RoutedEventArgs e)
{
DataTemplateKey key = new DataTemplateKey((sender as TabItem).Content.GetType());
DataTemplate fooTemplate = base.FindResource(key) as DataTemplate;
var PART_SelectedContentHost = this.tabControl.Template.FindName(
"PART_SelectedContentHost",
this.tabControl)
as ContentPresenter;
PART_SelectedContentHost.ApplyTemplate(); //АРХИВАЖНО!var _def1 = fooTemplate.FindName("def1", PART_SelectedContentHost);
var _def2 = fooTemplate.FindName("def2", PART_SelectedContentHost);
if (_def1 != null)
(_def1 as Label).Content = new Random().Next();
if (_def2 != null)
(_def2 as Label).Content = new Random().Next();
}
причем строка, помеченая АРХИВАЖНОЙ архиважно только в том случае, если вы пытаетесь искать ДатаТемплейт ВО ВРЕМЯ переключения вкладки, а не после завершения этого процесса.