WPF ContentControl Styling - wpf

How can I apply a style to the content of a contentcontrol. For example:
<Window.Resources>
<Controls:DataGrid x:Key="PersonDataGrid" AutoGenerateColumns="False" ItemsSource="{Binding .}" x:Shared="False">
<Controls:DataGrid.Columns>
<Controls:DataGridTextColumn Header="First Name" Binding="{Binding Path=FirstName}" IsReadOnly="True"/>
<Controls:DataGridTextColumn Header="Last Name" Binding="{Binding Path=LastName}" IsReadOnly="True"/>
</Controls:DataGrid.Columns>
</Controls:DataGrid>
</Window.Resources>
<StackPanel>
<ContentControl Content="{StaticResource PersonDataGrid}" DataContext="{Binding Path=Customers}" Style="DataGridStyle1"></ContentControl>
<ContentControl Content="{StaticResource PersonDataGrid}" DataContext="{Binding Path=Employees}" Style="DataGridStyle2"></ContentControl>
</StackPanel>

EDIT 2: It looks like you're trying to apply a different Style to each of your DataGrids. To do this, you're going to need to define their specific Style inside the Resources Section of each ContentControl. If the styles are defined elsewhere, you can always create a new style based on the style defined elsewhere as shown below
The first ContentControl's DockPanel's Background will be Black. The second's will be Blue.
<Window.Resources>
<Style TargetType="DockPanel" x:Key="DockStyle1">
<Setter Property="Background" Value="Black" />
</Style>
<Style TargetType="DockPanel" x:Key="DockStyle2">
<Setter Property="Background" Value="Blue" />
</Style>
<DockPanel x:Key="MyDockPanel">
<Rectangle Fill="Green" DockPanel.Dock="Top" Height="20" Width="50" />
<Rectangle Fill="Red" DockPanel.Dock="Top" Height="20" Width="20" />
<Rectangle Fill="Yellow" DockPanel.Dock="Bottom" Height="20" Width="50" />
</DockPanel>
</Window.Resources>
<StackPanel>
<StackPanel>
<ContentControl Content="{StaticResource MyDockPanel}">
<ContentControl.Resources>
<Style TargetType="{x:Type DockPanel}" BasedOn="{StaticResource DockStyle1}" />
</ContentControl.Resources>
</ContentControl>
<ContentControl Content="{StaticResource MyDockPanel}">
<ContentControl.Resources>
<Style TargetType="DockPanel" BasedOn="{StaticResource DockStyle2}" />
</ContentControl.Resources>
</ContentControl>
</StackPanel>
</StackPanel>
EDIT 3 - For your example, I think you want something like this (I can't test this however as I don't have access to your 'Controls' namespace):
<Window.Resources>
<Controls:DataGrid x:Key="PersonDataGrid" AutoGenerateColumns="False" ItemsSource="{Binding .}" x:Shared="False">
<Controls:DataGrid.Columns>
<Controls:DataGridTextColumn Header="First Name" Binding="{Binding Path=FirstName}" IsReadOnly="True"/>
<Controls:DataGridTextColumn Header="Last Name" Binding="{Binding Path=LastName}" IsReadOnly="True"/>
</Controls:DataGrid.Columns>
</Controls:DataGrid>
</Window.Resources>
<StackPanel>
<ContentControl Content="{StaticResource PersonDataGrid}" DataContext="{Binding Path=Customers}">
<ContentControl.Resources>
<Style TargetType="{x:Type Controls:DataGrid}" BasedOn="{StaticResource DataGridStyle1}" />
</ContentControl.Resources>
</ContentControl>
<ContentControl Content="{StaticResource PersonDataGrid}" DataContext="{Binding Path=Employees}">
<ContentControl.Resources>
<Style TargetType="{x:Type Controls:DataGrid}" BasedOn="{StaticResource DataGridStyle2}" />
</ContentControl.Resources>
</ContentControl>
</StackPanel>
Unfortunately, you cannot Style DataGridTextColumns as stated in Why can't I style a DataGridTextColumn?
Instead, I generally set the CellStyle of a DataGridTextColumn to 'style' it:
<Style TargetType="DataGridCell" x:Key="DataGridCenteredText">
<Setter Property="TextBlock.TextAlignment" Value="Center" />
</Style>
<DataGridTextColumn Header="Centered Text" CellStyle="{StaticResource DataGridCenteredText}" Binding="{Binding Path=MyData}" />
I think you'll need to define the CellStyle on a per column basis however (I can't think of any reason why you wouldn't anyway.)

Related

How can I edit the RowHeader in the DataGrid?

The text box under id still belongs to the header and I would like to change the yellow marked field next to the header from this DataGrid so that it looks like the green marked field on picture 2.
Picture1:
Picture2:
My Datagrid Xaml Code is this:
<DataGrid ItemsSource="{Binding Persons}" AutoGenerateColumns="False" Height="345" Margin="52,76,5,0" x:Name="gridd" Width="619" >
<DataGrid.Resources>
<Style TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="Background" Value="Gray"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="BorderBrush" Value="White"/>
<Setter Property="BorderThickness" Value="0,0,1,0" />
</Style>
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="BorderBrush" Value="Gray"/>
<Setter Property="BorderThickness" Value="0,0,1,0" />
</Style>
<Style TargetType="{x:Type DataGridRowHeader}">
<Setter Property="Width" Value="15"/>
<Setter Property="Height" Value="20"/>
<Setter Property="Background" Value="White"/>
<Setter Property="BorderBrush" Value="Gray"/>
<Setter Property="BorderThickness" Value="1,1,1,1"/>
</Style>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn Width="*" SortMemberPath="Id" Binding="{Binding Id}" CanUserResize="False" IsReadOnly="True">
<DataGridTextColumn.Header>
<StackPanel>
<TextBlock Text="Id" Margin="3 0 0 0" Width="148" Height="17"/>
<Separator Background="White" Width="125" />
<TextBox x:Name="IDSearcBox" Width="113" Height="19" Margin="0 0 0 2" Text="{Binding QueryforID, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Width="*" SortMemberPath="Id" Binding="{Binding Name}" CanUserResize="False" IsReadOnly="True">
<DataGridTextColumn.Header>
<StackPanel>
<TextBlock Text="Name" Margin="3 0 0 0" Width="148" Height="17"/>
<Separator Background="White" Width="125" />
<TextBox x:Name="Name" Width="113" Height="19" Margin="0 0 0 2" Text="{Binding Queryforname, UpdateSourceTrigger=PropertyChanged}"/>
</StackPanel>
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Width="*" SortMemberPath="Id" Binding="{Binding Country}" CanUserResize="False" IsReadOnly="True">
<DataGridTextColumn.Header>
<StackPanel>
<TextBlock Text="Land" Margin="3 0 0 0" Width="148" Height="17"/>
<Separator Background="White" Width="125"/>
<TextBox x:Name="Birthday" Width="113" Height="19" Margin="0 0 0 2" Text="{Binding QueryforCountry, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Width="*" SortMemberPath="Id" Binding="{Binding Location}" CanUserResize="False" IsReadOnly="True">
<DataGridTextColumn.Header>
<StackPanel>
<TextBlock Text="Ort" Margin="3 0 0 0" Width="148" Height="17"/>
<Separator Background="White" Width="125" />
<TextBox x:Name="Ort" Width="113" Height="19" Margin="0 0 0 2" Text="{Binding QueryforLocation, UpdateSourceTrigger=PropertyChanged}"/>
</StackPanel>
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn SortMemberPath="Id" Binding="{Binding Age}" CanUserResize="False" IsReadOnly="True">
<DataGridTextColumn.Header>
<StackPanel>
<TextBlock Text="Alter" Margin="0 0 0 0" Width="115" Height="17"/>
<Separator Background="White" Width="125"/>
<TextBox x:Name="alter" Width="119" Height="19" Margin="0 0 0 2" Text="{Binding QueryforAge, UpdateSourceTrigger=PropertyChanged}"/>
</StackPanel>
</DataGridTextColumn.Header>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
How did I need to change the DataGrid to get this look? I think i need to change something in the DataGrid.Resources Part but I dont know how to change Picture 1 to Picture2
Edit:
It now look like this but the Stack Panel i createt doesnt fill the entire Fild
You can restyle that Button in the header by defining a adding a Style with a specific ComponentResourceKey key to <DataGrid.Resources>, e.g.:
<Style x:Key="{ComponentResourceKey ResourceId=DataGridSelectAllButtonStyle, TypeInTargetAssembly={x:Type DataGrid}}"
TargetType="Button">
<Setter Property="Content">
<Setter.Value>
<TextBlock FontFamily="Segoe MDL2 Assets" Text="" />
</Setter.Value>
</Setter>
</Style>
You can set the Content property to whatever you want. The above TextBlock is just an example.
A minimal example to demonstrate:
<DataGrid>
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Mode=OneWay}"/>
</DataGrid.Columns>
<DataGrid.ItemsSource>
<x:Array Type="{x:Type sys:String}">
<sys:String>One</sys:String>
<sys:String>Two</sys:String>
<sys:String>Three</sys:String>
</x:Array>
</DataGrid.ItemsSource>
<DataGrid.RowHeaderTemplate>
<DataTemplate>
<Ellipse Width="10" Height="10" Fill="Red"/>
</DataTemplate>
</DataGrid.RowHeaderTemplate>
</DataGrid>
Instead of Ellipse, use the Image or Shape with Geometry you need.
In the upper left corner (to the left of the Columns Headers and above the Rows Header) there is a Button with a RoutedCommand Command =" {x: Static DataGrid.SelectAllCommand} ".
The button gets the style from the dynamic key Style ="{DynamicResource {ComponentResourceKey ResourceId = DataGridSelectAllButtonStyle, TypeInTargetAssembly = {x: Type DataGrid}}}".
Here is the complete definition of a button in the default template for DataGrid:
<Button Command = "{x: Static DataGrid.SelectAllCommand}"
Focusable = "false"
Style = "{DynamicResource {ComponentResourceKey ResourceId = DataGridSelectAllButtonStyle, TypeInTargetAssembly = {x: Type DataGrid}}}"
Visibility = "{Binding HeadersVisibility, ConverterParameter = {x: Static DataGridHeadersVisibility.All}, Converter = {x: Static DataGrid.HeadersVisibilityConverter}, RelativeSource = {RelativeSource AncestorType = {x: Type DataGrid}}}"
Width = "{Binding CellsPanelHorizontalOffset, RelativeSource = {RelativeSource AncestorType = {x: Type DataGrid}}}" />
You can override the button style in the DataGrid resources using this key:
<DataGrid>
<DataGrid.Resources>
<Style TargetType="Button" x:Key="{ComponentResourceKey ResourceId=DataGridSelectAllButtonStyle, TypeInTargetAssembly={x:Type DataGrid}}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Ellipse Width="10" Height="10" Fill="Green"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Mode=OneWay}" ClipboardContentBinding="{x:Null}"/>
</DataGrid.Columns>
<DataGrid.ItemsSource>
<x:Array Type="{x:Type sys:String}">
<sys:String>One</sys:String>
<sys:String>Two</sys:String>
<sys:String>Three</sys:String>
</x:Array>
</DataGrid.ItemsSource>
<DataGrid.RowHeaderTemplate>
<DataTemplate>
<Ellipse Width="10" Height="10" Fill="Red"/>
</DataTemplate>
</DataGrid.RowHeaderTemplate>
</DataGrid>
If you need another element instead of a Button, then for this you have to create your own template for the DataGrid.
Option for placing two elements vertically with a dividing line:
<DataGrid>
<DataGrid.Resources>
<Style TargetType="Button" x:Key="{ComponentResourceKey ResourceId=DataGridSelectAllButtonStyle, TypeInTargetAssembly={x:Type DataGrid}}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Ellipse Width="10" Height="10" Fill="Aqua"/>
<Rectangle Grid.Row="1" Fill="Yellow" Height="2" Margin="0 2"/>
<Ellipse Grid.Row="2" Width="10" Height="10" Fill="Green"/>
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</DataGrid.Resources>

WPF DataGrid column headers squeezed before ItemSource is set

I currently have a datagrid in WPF with only two columns, and its item source is set within the .cs codes when attempting to bind it to its specific item source, but initially it is not referenced to any itemsource. The problem is, if there is no item source yet, the columns are squeezed up even though i have specified the width of the columns. (in attached picture)
The columns are looking fine until i added the <datagrid.groupstyle> portion, may i ask if i am missing something or am i doing something wrong.
Below is the codes inside my .xaml for this datagrid.
<DataGrid Visibility="Visible"
x:Name="IFCInfoDataGrid" Width="auto" Height="auto" HeadersVisibility="Column"
AutoGenerateColumns="False" Margin="12" IsReadOnly="True" Grid.ColumnSpan="2"
SelectionUnit="FullRow" IsSynchronizedWithCurrentItem="False" >
<DataGrid.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
</Style>
</DataGrid.CellStyle>
<DataGrid.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<DockPanel Background="LightBlue">
<TextBlock Text="{Binding Path=Name}" Foreground="Blue" Margin="30,0,0,0" Width="100" />
</DockPanel>
</DataTemplate>
</GroupStyle.HeaderTemplate>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}" >
<Setter Property="Margin" Value="0,0,0,5" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander
BorderBrush="#FF002255"
IsExpanded="True"
Background="Tan"
BorderThickness="0,0,0,1">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock VerticalAlignment="Center" FontWeight="Bold" Text="{Binding Path=Name}" Width="200" />
</StackPanel>
</Expander.Header>
<Expander.Content>
<ItemsPresenter />
</Expander.Content>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</DataGrid.GroupStyle>
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding IFCParameter}" Header="IFC Parameter" Width="0.5*"
ElementStyle="{StaticResource DataGridRowStyle}" IsReadOnly="True" CanUserSort="False"/>
<DataGridTextColumn Binding="{Binding ParameterValue}" Header="Value" Width="0.5*"
ElementStyle="{StaticResource DataGridRowStyle}" IsReadOnly="True" CanUserSort="False"/>
</DataGrid.Columns>
</DataGrid>
Set the <GroupStyle.Panel> element to an ItemsPanelTemplate with a DataGridRowsPresenter:
<DataGrid.GroupStyle>
<GroupStyle>
<GroupStyle.Panel>
<ItemsPanelTemplate>
<DataGridRowsPresenter/>
</ItemsPanelTemplate>
</GroupStyle.Panel>
<GroupStyle.HeaderTemplate>
...
</GroupStyle.HeaderTemplate>
<GroupStyle.ContainerStyle>
...
</GroupStyle.ContainerStyle>
</GroupStyle>
</DataGrid.GroupStyle>

WPF: Grid inside DataGridTemplateColumn not expanding

I'm facing two problems with my projet:
SpackPanel not expanding the space available inside DataGridTemplateColumn
TextBlock not wrapping
I have a DataGrid with three different columns, and I want the one in the middle to use all available space left. Also in that column I have a StackPanel because I need to have two elements inside:
Border with icon inside that just appears depending on Use_Half_Portion value
TextBlock showing text
Giving background colors to the elements I have noticed that the StackPanel doesn't fill all of the available space left insite the column, and the wrap in the TextBlock is not being respected. Im supposing that the StackPanel is not assuming the MaxWidth of the DataGridTemplateColumn and it's using unlimited space, and because of that the TextBlock assumes that the limit is not being reached to make the text wrap.
Here's my code:
<DataGrid x:Name="ConsumptionList" ItemsSource="{Binding ConsumptionList}"
AutoGenerateColumns="False" IsReadOnly="True"
CanUserReorderColumns="False" CanUserResizeColumns="False"
BorderBrush="{x:Null}" VerticalContentAlignment="Center" CanUserSortColumns="False" HeadersVisibility="Column" Margin="0,0,0,-4" Background="{x:Null}">
<DataGrid.Resources>
<Style TargetType="{x:Type ScrollBar}" BasedOn="{StaticResource foScrollBar.Small}"/>
</DataGrid.Resources>
<DataGrid.ColumnHeaderStyle>
<StaticResource ResourceKey="clientScreenList.Header"/>
</DataGrid.ColumnHeaderStyle>
<DataGrid.RowStyle>
<StaticResource ResourceKey="clientScreenList.Lines"/>
</DataGrid.RowStyle>
<DataGrid.CellStyle>
<StaticResource ResourceKey="clientScreenList.Cells"/>
</DataGrid.CellStyle>
<DataGrid.Style>
<StaticResource ResourceKey="foBillingList"/>
</DataGrid.Style>
<DataGrid.Columns>
<!--quantity-->
<DataGridTextColumn x:Name="ConsQttColumn" MinWidth="20" Width="Auto" MaxWidth="80" FontFamily="Segoe UI Semibold"
Binding="{Binding Quantity, Converter={StaticResource DecimalToQuantityConverter}}" Header="{x:Static localization:LanguageRes.consList_quantity}" />
<!--description-->
<DataGridTemplateColumn x:Name="ConsDescriptionColumn" Header="Descrição" Width="*" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch" Background="#FFDC1A1A">
<Border CornerRadius="30" Grid.Column="0" Width="30" Height="30" Background="{x:Null}" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="0,0,3,0">
<Border.Style>
<Style TargetType="{x:Type Border}">
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding Use_Half_Portion}" Value="1">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<TextBlock Grid.Column="1" TextWrapping="Wrap" HorizontalAlignment="Center" Style="{StaticResource icon}" TextAlignment="Center" FontSize="22" Text="{x:Static TechUI:AppConstants+ICONS.HalfDose}" Padding="0"
Margin="0" Foreground="Black" Background="{x:Null}" />
</Border>
<TextBlock Text="{Binding Product_Description}" HorizontalAlignment="Left" TextAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Center" FontFamily="Segoe UI Semibold" Background="#FFB4AD1C" />
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<!-- total price-->
<DataGridTemplateColumn x:Name="ConsTotalColumn" Header="Preço Total" Width="Auto" MaxWidth="135">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left" MaxWidth="135" VerticalAlignment="Center" >
<TextBlock MaxWidth="135" HorizontalAlignment="Stretch" TextAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Center" FontFamily="Segoe UI Semibold" >
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Text" Value="{Binding Total_W_Vat, Converter={StaticResource DecimalToPriceConverter}}" />
<Style.Triggers>
<DataTrigger Binding="{Binding Is_Composite}" Value="1">
<Setter Property="Text" Value=" " />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
As you can see in the image, the red element is the StackPanel and the green element is the TextBlock. In the first line you can see that the text is being cut and not being wrapped, the full text is "Almondegas Frango"
I have found a solution.
Just changed the StackPanel for a DockPanel and it worked the exact same way I wanted!

Templated tooltip for DataGridCell depending on cell's content

I want to display tooltip of different view depending on content of DataGridCell. The following code works.
<DataGrid>
<DataGrid.Columns>
<DataGridTextColumn Header="1" Binding="{Binding}">
<DataGridTextColumn.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="ToolTip">
<Setter.Value>
<ToolTip>
<ToolTip.Content>
<TextBlock Foreground="Blue" Text="{Binding}"></TextBlock>
</ToolTip.Content>
</ToolTip>
</Setter.Value>
</Setter>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
</DataGrid.Columns>
<DataGrid.Items>
<system:String>AAA</system:String>
<system:Int32>2</system:Int32>
</DataGrid.Items>
</DataGrid>
But when I try using templates I have no success (I want select template basing on type of view model).
<DataGrid>
<DataGrid.Columns>
<DataGridTextColumn Header="1" Binding="{Binding}">
<DataGridTextColumn.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="ToolTip">
<Setter.Value>
<ToolTip>
<ToolTip.ContentTemplate>
<DataTemplate>
<ContentControl Content="{Binding}">
<ContentControl.Resources>
<DataTemplate DataType="system:String">
<TextBlock Foreground="Blue" Text="{Binding}"></TextBlock>
</DataTemplate>
<DataTemplate DataType="system:Int32">
<TextBlock Foreground="Red" Text="{Binding}"></TextBlock>
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
</DataTemplate>
</ToolTip.ContentTemplate>
</ToolTip>
</Setter.Value>
</Setter>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
</DataGrid.Columns>
<DataGrid.Items>
<system:String>AAA</system:String>
<system:Int32>2</system:Int32>
</DataGrid.Items>
</DataGrid>
How to fix it?
Bind the Content property of the Tooltip itself to the DataContext and use explicit type specifications using {x:Type}:
<DataGrid>
<DataGrid.Columns>
<DataGridTextColumn Header="1" Binding="{Binding}">
<DataGridTextColumn.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="ToolTip">
<Setter.Value>
<ToolTip Content="{Binding}">
<ToolTip.ContentTemplate>
<DataTemplate>
<ContentControl Content="{Binding}">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type system:String}">
<TextBlock Foreground="Blue" Text="{Binding}"></TextBlock>
</DataTemplate>
<DataTemplate DataType="{x:Type system:Int32}">
<TextBlock Foreground="Red" Text="{Binding}"></TextBlock>
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
</DataTemplate>
</ToolTip.ContentTemplate>
</ToolTip>
</Setter.Value>
</Setter>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
</DataGrid.Columns>
<DataGrid.Items>
<system:String>AAA</system:String>
<system:Int32>2</system:Int32>
</DataGrid.Items>
</DataGrid>

DataGrid not sizing correctly

As you can see, I have two DataGrids in my app. For reasons unknown, one or both of the grids will not be correctly sized when the application starts. (The images are loaded programmatically.)
Does anyone know why and, more importantly, a way to fix this issue?
An odd thing to note is that the grid resizes itself when the mouse scroll button is scrolled over it, but the scroll button does not scroll the grid (only page up/down and cursor keys do, except, of course, dragging the scrollbar). Also, even if the ScrollViewer is removed, the problem persists.
XAML
<UserControl x:Class="SW.ImagesControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:SW="clr-namespace:SW">
<UserControl.Resources>
<SW:NullImageConverter x:Key="NullImageConverter" />
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ScrollViewer HorizontalScrollBarVisibility="Visible" Grid.Row="1" Grid.ColumnSpan="2">
<DataGrid AutoGenerateColumns="False" IsReadOnly="True" Padding="0" Margin="0"
ItemsSource="{Binding}" SelectionUnit="Cell"
VirtualizingStackPanel.VirtualizationMode="Recycling" >
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}" />
<DataGridTemplateColumn Header="Image">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Command="{Binding ChangeImageCommand}">
<Button.Template>
<ControlTemplate>
<Grid>
<TextBlock Name="tb" HorizontalAlignment="Center" VerticalAlignment="Center" Visibility="Collapsed">
<Hyperlink Command="{Binding ChangeImageCommand}">Browse...</Hyperlink>
</TextBlock>
<Image Name="img" Source="{Binding Image, Converter={StaticResource NullImageConverter}}" Margin="0"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger SourceName="img" Property="Source" Value="{x:Null}">
<Setter TargetName="tb" Property="Visibility" Value="Visible"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Template>
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Preview">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image Source="{Binding PreviewImage, Converter={StaticResource NullImageConverter}}" Margin="0" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</ScrollViewer>
</Grid>
</UserControl
The DataGrid has an internal ScrollViewer, so the external one is unnecessary. This might not have been obvious, though, because VirtualizingStackPanel.VirtualizationMode was set to Recycling. Removing that attribute and the scrollviewer solves the sizing issue as well as the lack of scrolling.
<UserControl x:Class="SW.ImagesControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:SW="clr-namespace:SW">
<UserControl.Resources>
<SW:NullImageConverter x:Key="NullImageConverter" />
</UserControl.Resources>
<DataGrid AutoGenerateColumns="False" IsReadOnly="True" Padding="0" Margin="0"
ItemsSource="{Binding}" SelectionUnit="Cell" >
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}" />
<DataGridTemplateColumn Header="Image">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Command="{Binding ChangeImageCommand}">
<Button.Template>
<ControlTemplate>
<Grid>
<TextBlock Name="tb" HorizontalAlignment="Center" VerticalAlignment="Center" Visibility="Collapsed">
<Hyperlink Command="{Binding ChangeImageCommand}">Browse...</Hyperlink>
</TextBlock>
<Image Name="img" Source="{Binding Image, Converter={StaticResource NullImageConverter}}" Margin="0"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger SourceName="img" Property="Source" Value="{x:Null}">
<Setter TargetName="tb" Property="Visibility" Value="Visible"/>
<!--<Setter TargetName="img" Property="Visibility" Value="Collapsed"/>-->
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Template>
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Preview">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image Source="{Binding PreviewImage, Converter={StaticResource NullImageConverter}}" Margin="0" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</UserControl

Resources