I've been googling this for the last 2 days and cant get anywhere, I just cant do anything to any control in a datatemplate of a tabcontrol.
First off, the code:
private void Window_Loaded(object sender, RoutedEventArgs e) {
tabControl1.ItemsSource = new string[] { "TabA", "TabB", "TabC" };
}
private void tabControl1_SelectionChanged(object sender, SelectionChangedEventArgs e) {
ContentPresenter cp = tabControl1.Template.FindName("PART_SelectedContentHost", tabControl1) as ContentPresenter;
DataTemplate dt = tabControl1.ContentTemplate;
Grid g = tabControl1.ContentTemplate.FindName("myGrid", cp) as Grid;
g.Background = new SolidColorBrush(Colors.Red);
}
xaml
<Window x:Class="tabTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded">
<Grid>
<TabControl IsSynchronizedWithCurrentItem="True" Height="140" Name="tabControl1" Width="230" SelectionChanged="tabControl1_SelectionChanged">
<TabControl.ContentTemplate>
<DataTemplate>
<Grid x:Name="myGrid">
</Grid>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</Grid>
In short this line:
Grid g = tabControl1.ContentTemplate.FindName("myGrid", cp) as Grid;
throws an error "System.InvalidOperationException" This operation is valid only on elements that have this template applied.
this particular idea i got from here
I've found loads of other ways of doing this but I cant seem to get anywhere :( hope someone can point me in the right direction :)
We can not access DataTemplate controls in code behind. So for this you have to use ICommand interface inside your ViewModel. So it is clear that you should be use MVVM pattern. And important is that use of Command property is not a complex task. Can you please refer this links.
If it finds a DataTemplate that has a matching DataType but no key, it will use it to render the view model. If it doesn't find one, it'll default to rendering the ToString value of the object.
Since you're not being specific, WPF is attempting to walk up your logical tree to find an appropriate DataTemplate. When it finds it, it uses it to render the view model. Where it doesn't find it, it calls ToString and renders that.
Therefore, WPF searches for an appropriate DataTemplate for both. Since both contain an instance of your view model (that's their DataContext) then the same DataTemplate will be used to render tab headers and their contents. NOTE: you didn't explicitly state that this is what's happening in your question.
Looks like it's issue with the way the TabControl is being instantiated by the run time. It appears that the first time the SelectionChanged event is being raised the ContentTemplate is not quite ready to be accessed. If you run your code again and skip over the first access of ContentTemplate you'll see that in subsequent events you can access this property without the exception being thrown.
Often these types of errors can be overcome by calling Dispatcher.BeginInvoke, in this case it allows the run time to finish initializing the tab control before executing your code.
Dispatcher.BeginInvoke(new Action(() =>
{
ContentPresenter cp = tabControl1.Template.FindName("PART_SelectedContentHost", tabControl1) as ContentPresenter;
Grid g = tabControl1.ContentTemplate.FindName("myGrid", cp) as Grid;
g.Background = new SolidColorBrush(Colors.Red);
}));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With