Reputation: 37770
I have TreeView
, which displays some data using data templates. Here's XAML:
<TreeView Grid.Row="0" ItemsSource="{Binding Railways}" x:Name="tvDatawareObjects"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
</Style>
</TreeView.ItemContainerStyle>
<TreeView.Resources>
<!-- other templates here... -->
<HierarchicalDataTemplate DataType="{x:Type viewModels:ProjectViewModel}" ItemsSource="{Binding Phases}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Text="{Binding Model.Code}" FontWeight="DemiBold" />
<TextBlock Text="{Binding Model.Title}" TextWrapping="Wrap" Foreground="Gray" Grid.Row="1" />
</Grid>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type viewModels:CollectionViewModel}" ItemsSource="{Binding Items}">
<TextBlock Text="{Binding CollectionName}" />
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
Text wrapping for <TextBlock Text="{Binding Model.Title}" TextWrapping="Wrap" Foreground="Gray" Grid.Row="1" />
doesn't work. What am I doing wrong?
Upvotes: 3
Views: 2673
Reputation: 3803
I believe the TextBlock
isn't wrapping because it doesn't have a defined width. The grid column that the TextBlock
is in has a * width which will grow as the TextBlock
grows in width. Try setting a width on the TextBlock
or the column and see if the change causes the TextBlock
to wrap.
Update:
To be more specific, the problem is that the TreeViewItem
will size itself to the size of its contents, the ColumnDefinition
will fill the (infinitely) available space and the TextBlock
, with no width restriction, will never wrap. This post does a good job of describing how the TreeViewItem behaves. To sum it up: the content area of the TreeViewItem
is set to 'Auto' so it will grow to fit the contents. To explicitly set the width of the TreeViewItem
try binding your ColumnDefinition
width to the TreeView
's ActualWidth
.
XAML:
<TreeView Width="100">
<TreeViewItem>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding RelativeSource={RelativeSource AncestorType=TreeView}, Path=ActualWidth}"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Text="Lorem Ipsum" />
<TextBlock Text="Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book."
TextWrapping="Wrap" Grid.Row="1"/>
</Grid>
</TreeViewItem>
</TreeView>
Upvotes: 2
Reputation: 37770
I did it. :)
Accordind to the link, provided in the Dan's answer, the reason is lying in the default TreeViewItemTemplate.
Unfortunately, simple binding to TreeView.ActualWidth
can't help. This is because width of each item is less than TreeView.ActualWidth
by definition - items are rendered with some horizontal offset, depending on their level.
Hence, to solve the problem, I need to calculate width of item like this:
width = actual_width_of_tree_view - relative_horizontal_offset_of_item
To be more precise, I need ScrollViewer.ViewportWidth
, so as TreeViewContent might be scrolled vertically, and visible area of TreeView
will be less than TreeView.ActualWidth
in this case.
Here's attached property:
public static Double GetProjectTitleWidth(DependencyObject obj)
{
return (Double)obj.GetValue(ProjectTitleWidthProperty);
}
public static void SetProjectTitleWidth(DependencyObject obj, Double value)
{
obj.SetValue(ProjectTitleWidthProperty, value);
}
public static readonly DependencyProperty ProjectTitleWidthProperty = DependencyProperty.RegisterAttached(
"ProjectTitleWidth",
typeof(Double),
typeof(DatawareSearchView),
new UIPropertyMetadata(0.0, ProjectTitleWidthChanged));
private static void ProjectTitleWidthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var targetElement = d as FrameworkElement;
if (targetElement != null)
{
var bindingExpr = targetElement.GetBindingExpression(ProjectTitleWidthProperty);
var sourceElement = bindingExpr.DataItem as FrameworkElement;
if (sourceElement != null)
{
// calculating relative offset
var leftTop = targetElement.TranslatePoint(new Point(0.0, 0.0), sourceElement);
// trying to find ScrollViewer
var border = VisualTreeHelper.GetChild(sourceElement, 0);
if (border != null)
{
var scrollViewer = VisualTreeHelper.GetChild(border, 0) as ScrollViewer;
if (scrollViewer != null)
{
// setting width of target element
targetElement.Width = scrollViewer.ViewportWidth - leftTop.X;
}
}
}
}
}
...and markup:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Text="{Binding Model.Code}" FontWeight="DemiBold" />
<TextBlock Text="{Binding Model.Title}" TextWrapping="Wrap" Foreground="Gray" x:Name="tbTitle" Grid.Row="1"
localviews:DatawareSearchView.ProjectTitleWidth="{Binding RelativeSource={RelativeSource AncestorType=TreeView}, Path=ActualWidth}"/>
</Grid>
Of course, provided solution isn't universal - it assumes, that TreeView has Border
and ScrollViewer
.
Upvotes: 1
Reputation: 20461
try this
<TextBlock Text="{Binding Model.Title}" Width="{Binding ActualWidth,
ElementName=tvDatawareObjects}" TextWrapping="Wrap" Foreground="Gray" Grid.Row="1"/>
Upvotes: -2