The issue arises when I have disabled horizontal scrollbar (shown below) by using ScrollViewer.HorizontalScrollBarVisibility="Disabled", so all columns should fit.
I have 4 columns in my DataGrid. The first one has its Width set to "*", while other 3 Width is "Auto". There are buttons in the 3rd and 4th columns. The 3rd column contains two buttons one of which can has its Visibility set to Collapsed.
When first shown on the screen, two last columns with buttons overlap each other like shown in the picture below:
As you can see, there is more than enough space in the DataGrid.
If I resize the window or change the DataGrid's Visibility, next time it appears the columns will display properly.
Code:
<DataGrid AutoGenerateColumns="False" IsReadOnly="True" CanUserAddRows="False" CanUserReorderColumns="False" CanUserResizeColumns="False" CanUserResizeRows="False" HeadersVisibility="Column" SelectionUnit="FullRow" GridLinesVisibility="Horizontal" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.CanContentScroll="False" Margin="5">
<DataGrid.Columns>
<DataGridTemplateColumn Width="*">
<DataGridTemplateColumn.HeaderTemplate>
<DataTemplate>
<TextBlock Text="Text" />
</DataTemplate>
</DataGridTemplateColumn.HeaderTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Text}" TextTrimming="WordEllipsis" VerticalAlignment="Center" Padding="5" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Width="Auto">
<DataGridTemplateColumn.HeaderTemplate>
<DataTemplate>
<TextBlock Text="Enabled" />
</DataTemplate>
</DataGridTemplateColumn.HeaderTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsEnabled}" HorizontalAlignment="Center" VerticalAlignment="Center" Padding="5" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Width="Auto">
<DataGridTemplateColumn.HeaderTemplate>
<DataTemplate>
<TextBlock Text="Order" />
</DataTemplate>
</DataGridTemplateColumn.HeaderTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Button Command="{Binding Data.MoveOptionUpCommand, Source={StaticResource BindingProxy}}" CommandParameter="{Binding}" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5">
<Button.Style>
<Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Visibility" Value="Collapsed" />
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
<Image Source="/Resources/Images/Images16/Up.png" />
</Button>
<Button Command="{Binding Data.MoveOptionDownCommand, Source={StaticResource BindingProxy}}" CommandParameter="{Binding}" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5">
<Button.Style>
<Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Visibility" Value="Collapsed" />
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
<Image Source="/Resources/Images/Images16/Down.png" />
</Button>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Width="Auto">
<DataGridTemplateColumn.HeaderTemplate>
<DataTemplate>
<TextBlock Text="Actions" />
</DataTemplate>
</DataGridTemplateColumn.HeaderTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Button Command="{Binding Data.ShowOptionEditAreaCommand, Source={StaticResource BindingProxy}}" CommandParameter="{Binding}" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5">
<Image Source="/Resources/Images/Images16/Edit.png" />
</Button>
<Button Command="{Binding Data.RemoveOptionsCommand, Source={StaticResource BindingProxy}}" CommandParameter="{Binding}" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5">
<Image Source="/Resources/Images/Images16/Remove.png" />
</Button>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
Edit: added XAML code.
Related
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!
I have a DataGrid with following XAML. First of all the Button inside the grid doesn't get a blue styling and secondly when the button is pressed, the Command property is not working but the OnClick is working. In the view model I have RelayCommand implementation which works well with other controls only the button in the DataGrid seems to have an issue.
<DataGrid
x:Name="dgEntities"
Width="650"
Height="239"
Margin="40,-48,65,-8"
ItemsSource="{Binding JobEntities}"
AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Status">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button
Margin="5"
Content="{Binding TaskDetails[0].Status,Mode=TwoWay,NotifyOnTargetUpdated=True}"
Command="{Binding HypelinkCommand}"
CommandParameter="{Binding ElementName=dgEntities,Path=SelectedItem}"
Cursor="Hand"
Click="Button_Click">
<Button.Template>
<ControlTemplate TargetType="Button">
<TextBlock TextDecorations="Underline">
<ContentPresenter />
</TextBlock>
</ControlTemplate>
</Button.Template>
<Button.Style>
<Style TargetType="Button">
<Setter Property="Foreground" Value="Blue" />
</Style>
</Button.Style>
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn>
<DataGridTemplateColumn.Header>
<CheckBox Name="chkHeaderExtract" Checked="ChkHeaderExtract_OnChecked" Unchecked="ChkHeaderExtract_OnUnchecked"/>
</DataGridTemplateColumn.Header>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox Name="chkExtract" IsChecked="{Binding TaskDetails[0].IsSelected,Mode=TwoWay,NotifyOnTargetUpdated=True}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Status">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button
Margin="5"
Content="{Binding TaskDetails[1].Status,Mode=TwoWay,NotifyOnTargetUpdated=True}"
Command="{Binding HypelinkCommand}"
CommandParameter="{Binding ElementName=dgEntities,Path=SelectedItem}"
Cursor="Hand">
<Button.Template>
<ControlTemplate TargetType="Button">
<TextBlock TextDecorations="Underline">
<ContentPresenter />
</TextBlock>
</ControlTemplate>
</Button.Template>
<Button.Style>
<Style TargetType="Button">
<Setter Property="Foreground" Value="Blue" />
</Style>
</Button.Style>
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn>
<DataGridTemplateColumn.Header>
<CheckBox Name="chkHeaderTransform" Checked="ChkHeaderTransform_OnChecked" Unchecked="ChkHeaderTransform_OnUnchecked"/>
</DataGridTemplateColumn.Header>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox Name="chkTransform" IsChecked="{Binding TaskDetails[1].IsSelected,Mode=TwoWay,NotifyOnTargetUpdated=True}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Status">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button
Margin="5"
Content="{Binding TaskDetails[2].Status,Mode=TwoWay,NotifyOnTargetUpdated=True}"
Command="{Binding HypelinkCommand}"
CommandParameter="{Binding ElementName=dgEntities,Path=SelectedItem}"
Cursor="Hand"
Foreground="Blue">
<Button.Template>
<ControlTemplate TargetType="Button">
<TextBlock TextDecorations="Underline">
<ContentPresenter />
</TextBlock>
</ControlTemplate>
</Button.Template>
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn>
<DataGridTemplateColumn.Header>
<CheckBox Name="chkHeaderLoad" Checked="ChkHeaderLoad_OnChecked" Unchecked="ChkHeaderLoad_OnUnchecked"/>
</DataGridTemplateColumn.Header>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox Name="chkLoad" IsChecked="{Binding TaskDetails[2].IsSelected,Mode=TwoWay,NotifyOnTargetUpdated=True}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Binding="{Binding EntityName}" Header="Entity" Width="150"/>
</DataGrid.Columns>
</DataGrid>
CODE as posted as comment instead of update to original post.
private RelayCommand<object> _hyperlinkInstance;
public ICommand HypelinkCommand
{
get
{
if(_hyperlinkInstance==null)
_hyperlinkInstance = new RelayCommand<object>(openDialog);
return _hyperlinkInstance;
}
}
private void openDialog(object obj)
{
JobConfigurationResults results = obj as JobConfigurationResults;
jeresult = JobEntities.SingleOrDefault(
x => x.JobEntityId == results.JobEntityId);
}
I have an hierarchical Treeview which each item contains a complexed entity which consists of:
Border
-- Check box
-- TextBlock
i want to change the opacity of the border whenever the checkbox IsEnabled property is set to "False"
this is what i have:
<HierarchicalDataTemplate DataType="{x:Type sd:LegendTreeViewItem}" ItemsSource="{Binding Path=SubSensors}">
<Border x:Name="treeViewItemBorder" Height="24" Margin="3 3 3 3" Width="350" Background="{Binding Path=Color}" CornerRadius="8 8 8 8">
<StackPanel Orientation="Horizontal">
<CheckBox x:Name="treeViewItemCheckbox" Margin="5 5 5 5" Click="CheckBox_Click" IsChecked="{Binding IsChecked}" VerticalAlignment="Center" IsEnabled="{Binding Enabled}" Style="{StaticResource OpacityOnDisabled}"/>
<TextBlock Height="Auto" FontFamily="Tahoma" FontWeight="Bold" Foreground="Black" HorizontalAlignment="Left" Text="{Binding Path=Name}"
VerticalAlignment="Center" ToolTip="{Binding Path=Name}"/>
</StackPanel> </Border>
</HierarchicalDataTemplate>
<TreeView x:Name="legendTypeTree" Grid.Row="1" Foreground="White" ItemsSource="{Binding ElementName=uc, Path=TypeItemsSource}">
<TreeView.Resources>
<Style x:Key="OpacityOnDisabled" TargetType="{Binding RelativeSource={RelativeSource AncestorType=Border}}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsEnabled}" Value="False">
<Setter Property="Border.Opacity" Value="0.3"/>
<Setter Property="Border.Background" Value="White"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TreeView.Resources>
</TreeView>
Move both HierarchicalDataTemplate and Style for the Border in the TreeView resources. (Style first in order for the StaticResource OpacityOnDisabled to resolve properly).
You want to change the style of the border, so there is no sense to apply style on the checkbox. Move Style="{StaticResource OpacityOnDisabled}" from the CheckBox to the Border element. Set the correct type of the style and for the DataTrigger change the bindinig to Binding="{Binding ElementName=treeViewItemCheckbox, Path=IsChecked}"
In the end you should have something like, which should do what you want:
Result:
<TreeView
x:Name="legendTypeTree"
Grid.Row="1"
Foreground="White"
ItemsSource="{Binding ElementName=uc, Path=TypeItemsSource}">
<TreeView.Resources>
<Style x:Key="OpacityOnDisabled" TargetType="{x:Type Border}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=treeViewItemCheckbox, Path=IsChecked}" Value="False">
<Setter Property="Border.Opacity" Value="0.3"/>
<Setter Property="Border.Background" Value="White"/>
</DataTrigger>
</Style.Triggers>
</Style>
<HierarchicalDataTemplate DataType="{x:Type sd:LegendTreeViewItem}" ItemsSource="{Binding Path=SubSensors}">
<Border
x:Name="treeViewItemBorder"
Height="24"
Margin="3 3 3 3"
Width="350"
Background="{Binding Path=Color}"
CornerRadius="8 8 8 8"
Style="{StaticResource OpacityOnDisabled}">
<StackPanel Orientation="Horizontal">
<CheckBox
x:Name="treeViewItemCheckbox"
Margin="5 5 5 5"
Click="CheckBox_Click"
IsChecked="{Binding IsChecked}"
VerticalAlignment="Center"
IsEnabled="{Binding Enabled}" />
<TextBlock
Height="Auto"
FontFamily="Tahoma"
FontWeight="Bold"
Foreground="Black"
HorizontalAlignment="Left"
Text="{Binding Path=Name}"
VerticalAlignment="Center"
ToolTip="{Binding Path=Name}"/>
</StackPanel>
</Border>
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
I have a data grid built using DataGridTemplateColumns. When a validation error exists, we are displaying it on the Textblock of the CellTemplate. When scrolling occurs, the error styling is lost after it scrolls off the page.
In my control resources:
<ControlTemplate x:Key="validationTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Foreground="Yellow"
FontSize="20"
VerticalAlignment="Center"
Margin="0,0,2,2">!</TextBlock>
<Border Grid.Column="1"
BorderBrush="Yellow"
BorderThickness="1"
Margin="0"
Padding="0"
Height="19">
<AdornedElementPlaceholder/>
</Border>
</Grid>
</ControlTemplate>
<Style x:Key="TextBlockValidationStyle" TargetType="{x:Type TextBlock}">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={RelativeSource Self},
Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
And Within the DataGrid:
<DataGridTemplateColumn Header="Destination Column">
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox IsEditable="True"
IsTextSearchCaseSensitive="{Binding ElementName=caseSensitiveSearch, Path=IsChecked}"
ItemsSource="{Binding AllSuggestedNames}"
TextSearch.TextPath="SuggestedName"
Text="{Binding ColumnMapping.DestinationColumnName, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Style="{StaticResource TextBlockValidationStyle}"
Text="{Binding ColumnMapping.DestinationColumnName,
ValidatesOnDataErrors=True,
NotifyOnValidationError=True,
UpdateSourceTrigger=PropertyChanged}"
Validation.ErrorTemplate="{StaticResource validationTemplate}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Solved it! Wrapping each CellTemplate's interior of their DataTemplate with an AdornerDecorator fixed it right up!
<DataTemplate>
<AdornerDecorator>
<TextBlock Style="{StaticResource TextBlockValidationStyle}"
Text="{Binding ColumnMapping.DestinationColumnName,
ValidatesOnDataErrors=True,
NotifyOnValidationError=True,
UpdateSourceTrigger=PropertyChanged}"
Validation.ErrorTemplate="{StaticResource validationTemplate}"/>
</AdornerDecorator>
</DataTemplate>
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