How do I enable text wrapping on all column headers? - wpf

How does one enable text wrapping on all column headers of a DataGrid, without disabling the other default header functionality? Such as column resizing, sort direction indicator, etc which are needed.
Is there a way to do this?

Or don't bother with the primitives in the app.xaml file and do the following (my objects):
<DataGrid Name="WBdataGrid" AutoGenerateColumns="False" ColumnHeaderHeight="50" >
<DataGrid.ColumnHeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock TextWrapping="Wrap" Text="{Binding}"></TextBlock>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</DataGrid.ColumnHeaderStyle>
<DataGrid.Columns> ...

I would like to enable text wrapping
on all column headers of my DataGrid,
without disabling the other default
header functionality
You need to add the following namespace to your app.xaml file:
xmlns:primitives="clr-namespace:Microsoft.Windows.Controls.Primitives;assembly=WPFToolkit"
and then add this tag to app.xaml:
<Style TargetType="{x:Type primitives:DataGridColumnHeader}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock TextWrapping="Wrap" Text="{Binding}"></TextBlock>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
This will add text-wrapping to the headers of all of your DataGrids throughout your WPF application.
While we're on the subject, if you just wanted to center the text of each of your DataGrid headers, you could do this using the following style instead:
<Style TargetType="{x:Type primitives:DataGridColumnHeader}">
<Setter Property="HorizontalContentAlignment" Value="Center"></Setter>
</Style>
Yet I've seen so many WPF articles suggesting that you can only do this by adding TextWrapping or HorizontalAlignment on each DataGrid column individually:
<toolkit:DataGridTextColumn Binding="{Binding Path=TaxAmount}">
<toolkit:DataGridTextColumn.HeaderTemplate >
<DataTemplate>
<TextBlock Text="Tax Amount" Width="90" TextWrapping="Wrap" HorizontalAlignment="Center"/>
</DataTemplate>
</toolkit:DataGridTextColumn.HeaderTemplate>
</toolkit:DataGridTextColumn>

I added
to the header text where I want the text to wrap. This is useful when you don't need to bind your header text to something
<DataGridTextColumn x:Name="cAccountNumber"
Header="Account
Number"
Width="80"
Binding="{Binding Path=AccountNumber}" />

Instead of assigning the column name directly to the DataGridColumn.Header property, I created a TextBlock containing the column name, set the TextWrapping property of the TextBlock to "Wrap" and assigned the TextBlock to the DataGridColumn.Header property. This preserves the default header functionality.
Example:
<toolkit:DataGridTextColumn Binding="{Binding Path=MyProperty}">
<toolkit:DataGridTextColumn.Header>
<TextBlock Text="Something Longer" TextWrapping="Wrap" />
</toolkit:DataGridTextColumn.Header>
</toolkit:DataGridTextColumn>

You could create a global Style for your column headers. Without any example mark-up I don't know the syntax, but it should look something like this:
<Style TargetType="{x:Type dg:ColumnHeader}">
<Setter Property="TextWrapping" Value="Wrap"/>
</Style>
Since the Style is key-less, it will automatically be applied to all of your column headers. And styles will not override any locally set properties, so it won't "disable" any existing header functionality.

Related

Excess border selection in WPF's Lisbox [duplicate]

I have a ListBox in which each item is a StackPanel. The StackPanel consist of an Image and a TextBlock below it:
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="10">
<Image>
<Image.Source>
<BitmapImage UriSource="{Binding Path=ImageFilePath}"/>
</Image.Source>
</Image>
<TextBlock Text="Title" TextAlignment="Center"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
It looks like this:
When the user select an item, I get the default blue rectangle that surround the StackPanel:
Now, I want to make a different border for the selected-item, but I want it to surround only the image.
I know how to make a control template and put a custom border around the ContentPresenter, but this, of course, will surround the whole StackPanel, not only the Image.
I don’t know if making changes to the ContentPresenter is possible, and if it is a good idea at all. If there is other way to achieve the look I want, it will be fine as well.
Right, the ListBox's own ContentPresenter isn't helpful for what you're doing. You want to a) eliminate the ListBox's own selection visuals and b) replace them with something more suitable in the DataTemplate for your items.
The default selection visual is applied by the default template for ListBoxItem. So replace that template. Using a Style in the resources for your ListBox, apply your own control template to ListBoxItem. Not much to it, just present the content and don't provide a selection background. Then you handle the selection visuals with a trigger in your data template, where your image and your label are defined and you can apply changes to one and not the other. The below example works for me.
Note that there's some fiddling with the HorizontalAlignment on the Border element to make it cling to the Image element within it. Also, I wrote a quickie test viewmodel whose Items property is called Items; I assume this is not the name of the collection member you're using to populate your own ListBox.
<ListBox
Margin="8"
ItemsSource="{Binding Items}"
>
<ListBox.Resources>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Grid>
<ContentPresenter />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.Resources>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Border
x:Name="HighlightBorder"
BorderThickness="4"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Margin="10"
>
<Border.Style>
<Style TargetType="Border">
<!-- MUST set default BorderBrush via a style, if you set it at all.
As an attribute on the Border tag, it would override the effects of
the trigger below.
-->
<Setter Property="BorderBrush" Value="Transparent" />
</Style>
</Border.Style>
<Image Source="{Binding ImageFilePath}" />
</Border>
</Grid>
<DataTemplate.Triggers>
<DataTrigger
Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=ListBoxItem}}"
Value="True">
<Setter TargetName="HighlightBorder" Property="BorderBrush" Value="Orange" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

The typed characters not visible when row height in silverlight DataGrid is reduced

I have a silverlight datagrid whose row height and font are to be reduced because more number of rows are to be displayed in it without increasing the total height.
I have set its row height to 15 and font size to 10. All its content is visible clearly, but when I type in some text in one of its cells, the typed content is not visible as I am typing it. When I am done typing the text and press , I can see it.
This is how it looks when I am typing some text in one of its cells:
How can I fix this?
Edit: The relevant part from the .xaml:
<sdk:DataGrid AutoGenerateColumns="False" Height="171" HorizontalAlignment="Left" Name="StockistClaimDetailsGrid" VerticalAlignment="Top" Width="756" Margin="0,20,0,0" RowHeight="15">
<sdk:DataGrid.Columns>
<sdk:DataGridTemplateColumn Header="" Width="30" >
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox Height="16" x:Name="CheckBox" Checked="CheckBox_Checked" IsChecked="{Binding IsChecked, Mode=TwoWay}" IsEnabled="{Binding CheckBoxEnabled, Mode=TwoWay}" Tag="{Binding}" />
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
</sdk:DataGridTemplateColumn>
<sdk:DataGridTextColumn x:Name="Remarks" Binding="{Binding Remarks}" Header="Remarks" IsReadOnly="False" Width="300" FontSize="10" />
</sdk:DataGrid.Columns>
</sdk:DataGrid>
The DataGrid uses two different TextBox instances for just displaying a cell's content and for editing it. So I guess the text style settings got applied to the displaying TextBox but not to the editing TextBox.
So, how to fix this?
I found the property EditingElementStyle on msdn. This seems to do the trick.
Just assign the same TextBoxStyle.
<Style x:Key="SmallTextBoxStyle" TargetType="TextBox">
<Setter Property="FontSize" Value="10"/>
</Style>
...
<sdk:DataGridTextColumn EditingElementStyle="{StaticResource SmallTextBoxStyle}" FontSize="10"/>
[Edit] I just found out that the ElementStyle must be applyable to TextBlock. So you cannot reused the Style, but you can duplicate the style and set the TaregtType accordingly. Or just omit the ElementStyle and set the FontSize on the column as seen above.
<Style x:Key="SmallTextBlockStyle" TargetType="TextBlock">
<Setter Property="FontSize" Value="10"/>
</Style>
<Style x:Key="SmallTextBoxStyle" TargetType="TextBox">
<Setter Property="FontSize" Value="10"/>
</Style>
...
<sdk:DataGridTextColumn
ElementStyle="{StaticResource SmallTextBlockStyle}"
EditingElementStyle="{StaticResource SmallTextBoxStyle}"/>

How to Bind ListViewItem's ToolTip to a ToolTip of TextBlock inside its ContentTemplate

I would like to bind my ListViewItem's ToolTip to its ContentTemplate's TextBlock's ToolTip.
I tried the following but it didnt work:
<ListView ItemsSource="{Binding DoestMatter}" >
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="ToolTip" Value="{Binding ElementName=Title, Path=ToolTip}"/>
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock x:Name="Title" Text="{Binding Title}" ToolTip="Test"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
</ListView>
The ToolTip's value is dynamically generated, here I just showed it as static string but actually it isn't, and that's why I need to bind it to the TextBlock's ToolTip.
How can I make it work?
Your code works just fine as it is... well, I had to change some Bindings to get it to work, but the main XAML is fine:
<ListView ItemsSource="{Binding Tests}" >
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="ToolTip" Value="{Binding ToolTip, ElementName=Title}" />
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock x:Name="Title" Text="{Binding Name}"
ToolTip="Test" />
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
</ListView>
However, one thing that I did notice was that it only works if you put your cursor directly over the TextBlock and that was not stretching across the width of the ListViewItem. To fix that, just set the HorizontalContentAlignment property to Stretch:
<ListView ItemsSource="{Binding Tests}" >
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="ToolTip" Value="{Binding ToolTip, ElementName=Title}" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock x:Name="Title" Text="{Binding Name}"
ToolTip="Test" />
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
</ListView>
UPDATE >>>
You're right... the ToolTip was still on the TextBlock. Then you just need to update your ToolTip.Binding to *the same value that works on the Text property:
<ListView ItemsSource="{Binding Tests}" >
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="ToolTip" Value="{Binding ToolTip}" />
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock x:Name="Title" Text="{Binding Title}"
ToolTip="{Binding ToolTip}" />
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
</ListView>
Now you should see 2 tooltips, one when over the TextBlock and one when over the ListViewItem.
UPDATE 2 >>>
#Ron, I really cannot understand why you are taking such a negative reaction to my answer(s)... you really should watch your attitude, because I am trying to help you and I don't feel that I deserve your bad attitude. So, to address your second, even ruder comment:
I said that the HorizontalAlignment is set to Stretch by default
Really? Where did you say that? In fact, you didn't say that, you said The ListViewItem stretches on default, which is something entirely different. As mentioned in the comment, I was stretching the TextBlock inside the ListViewItem with the HorizontalContentAlignment property, which isn't set to Strecth by default.
Who said that I want the Title as my ToolTip?
Nobody said that, but you did say The ToolTip's value is dynamically generated... so I can only image that you are Binding your dynamically generated ToolTip. If this is so, then you can simply data Bind that same value to the ListViewItem.ToolTip property as well.
UPDATE 3 >>>
In response to your last comment:
I stick to my question from the beginning because I cant really explain the problem. I know whats the solution though I dont know the practical way. I want to bind to the TextBlock's ToolTip Property.
Well sorry, but you can't do that in XAML because the TextBlock is declared in a DataTemplate. You can only access DataTemplate generated elements in code because they don't just exist until runtime... see the How to: Find DataTemplate-Generated Elements page on MSDN to find out how to do that. So you'll have to find another way to achieve your goal and that's why I've been suggesting these other methods all along.

silverlight column header disappers on applying header style template

I have a Silverlight DataGrid with two columns. The headers of these two columns header have to be shown with a text box and column header title or name so that the text box can be used for filtering later.
So, I have used the following code to display the text box using a style:
<Style x:Name="mytemplate"
x:Key="mytemplate"
xmlns:dataprimitives="clr-namespace:System.Windows.Controls.Primitives;assembly=System.Windows.Controls.Data"
TargetType="dataprimitives:DataGridColumnHeader">
<Setter Property="ContentTemplate" >
<Setter.Value>
<DataTemplate x:Name="ColHeaderTemplategrid">
<StackPanel>
<TextBox x:Name="txtfilterBox" KeyDown="txtfilterBox_KeyDown" Width="40"/>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
and I have applied the style to the column headers as below:
((DataGridTextColumn)column[0]).HeaderStyle = mytemplate;
((DataGridTextColumn)column[1]).HeaderStyle = mytemplate;
The thing is, now the text box is visible but the column header title or name disappears?
How do I show my column header along with the text box?
As u said i just inserted textblock in to the stackpanel of the template and solves the problem
the code is below
<Style x:Name="mytemplate" x:Key="mytemplate" xmlns:dataprimitives="clr-namespace:System.Windows.Controls.Primitives;assembly=System.Windows.Controls.Data"
TargetType="dataprimitives:DataGridColumnHeader">
<Setter Property="ContentTemplate" >
<Setter.Value>
<DataTemplate x:Name="ColHeaderTemplategrid">
<StackPanel>
<TextBlock Text="{Binding}" ></TextBlock>
<TextBox x:Name="txtfilterBox" KeyDown="txtfilterBox_KeyDown" Width="40"/>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>

How to specify a ToolTip for a control in a Style from XAML?

I'm using a the WPF datagrid from the Microsoft CodePlex project. I have a custom control that I want to databind to a field from the row of the datagrid. I can't for the life of me figure out how to specify a tooltip on a datagrid row.
The closest I've come is to use a RowStyle with a Setter to set the tooltip, but this only seems to work for text. When I try to put a ControlTempalte in as the Value for the ToolTip, it displays the result of calling ToString on the ControlTemplate type.
I think I need to set the "Template" property of the ToolTip, but I can't seem to figure out how to do that...
<dg:DataGrid Name="dgResults" AutoGenerateColumns="True">
<dg:DataGrid.RowStyle >
<Style TargetType="{x:Type dg:DataGridRow}">
<Setter Property="ToolTip" >
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToolTip}">
<StackPanel>
<TextBlock>txt1</TextBlock><TextBlock>txt2</TextBlock>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</dg:DataGrid.RowStyle>
</dg:DataGrid>
Figured it out... took me about 6 hours...
For some reason, I can't set the value directly using Value.Setter. If I define the content for the tooltip as a static resource though, and then set it in the Style property of the DataGrid.RowStyle it works.
So, the datagrid row style looks like:
<Style TargetType="{x:Type dg:DataGridRow}">
<Setter Property="ToolTip" Value="{StaticResource resKWIC}">
</Setter>
</Style>
</dg:DataGrid.RowStyle>
And the resource is
<Window.Resources>
<StackPanel x:Key="resKWIC">
<TextBlock>f1</TextBlock>
<TextBlock>f2></TextBlock>
</StackPanel>
</Window.Resources>
Thanks!
The key is to use the Property ToolTipService.ToolTip, instead of ToolTip - like this:
<Setter Property="ToolTipService.ToolTip" Value="My Tooltip"/>
I also got this working with a couple of changes; included incase it helps someone.
My Datadrid is bound to a list of custom objects, I wanted to display the string "Name" as a column and the string "text" in the tooltip. The trick for me (newbe) was that I had to include the Text Column and hide it for it to show up in the tooltip, i.e.:
<DataGrid AutoGenerateColumns="False" CanUserAddRows="False" EnableRowVirtualization="False" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" IsReadOnly="True" IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding}" Name="dgrTextGroupText" VerticalContentAlignment="Stretch" Grid.Column="3" Grid.Row="1" Grid.RowSpan="6" CanUserReorderColumns="False" CanUserSortColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Name}" Width="*" />
<DataGridTextColumn Binding="{Binding Text}" Width="0" Visibility="Hidden" />
</DataGrid.Columns>
<DataGrid.RowStyle>
<Style TargetType="{x:Type DataGridRow}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=DataContext.text}" />
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
</DataGrid>
Not sure you can do it through XAML.
A easier way might be to just handle the LoadingRow event. In xaml have something like:
<dg:DataGrid Name="dgResults" AutoGenerateColumns="True"
LoadingRow="dgResults_LoadingRow"
ItemsSource="{Binding ListOfStrings}" />
Then in code behind
void dgResults_LoadingRow(object sender, DataGridRowEventArgs e)
{
DataGridRow row = e.Row;
row.ToolTip = row.DataContext as string;
}
Obviously you will have to change the code depending on how you are populating the data in the datagrid. This is also untested =)
I needed to set the tooltip dynamically based on the cell content. I'm using the tooltip to display text overflow text from the cell. The binding below is from a c# class property named CellText. Thanks to the posts above for allowing me to avoid figuring out the entire thing myself.
<DataGridTextColumn Header="HeaderText" Binding="{Binding DisplayText, Mode=OneWay}" Width="33*">
<DataGridTextColumn.CellStyle>
<Style>
<Setter Property="ToolTipService.ToolTip" Value="{Binding DisplayText, Mode=OneWay}"/>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
There's no need for the ControlTemplate. If you want the StackPanel in the ToolTip, just set it as:
<Setter Property="ToolTip">
<Setter.Value>
<StackPanel>
<TextBlock>txt1</TextBlock><TextBlock>txt2</TextBlock>
</StackPanel>
</Setter.Value>
</Setter>

Resources