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);
}
Related
Is it possible to load a different data template for a defined column in a WPF data grid?
My XAML looks like this:
<DataGridTemplateColumn Header="Select">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox
HorizontalContentAlignment="Center"
Visibility="{Binding IsStarted}"
VerticalAlignment="Center"
IsChecked="{Binding IsStarted, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Command="{Binding DataContext.Checked,RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"
CommandParameter="{Binding}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
The goal here is load a separate data template when the binding IsStarted is set to false, In other words when the visibility is set to false.
The intended purpose here is when a certain button is triggered which will set the boolean to "false" another data template will be visible on this very own column instead of the currently existing items.
As an example, the following XAML should be displayed once the boolean is set to false after the execution of the button,
<TextBlock Visibility="{Binding IsTrue}" Text="Hello" />
Is this possible?
You could replace the CheckBox in the DataTemplate with a ContentControl and use a Style with a DataTrigger to replace its ContentTemplate based on the value of the IsStarted parameter:
<DataGridTemplateColumn Header="Select">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ContentControl Content="{Binding}">
<ContentControl.Style>
<Style TargetType="ContentControl">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<CheckBox
HorizontalContentAlignment="Center"
Visibility="{Binding IsStarted}"
VerticalAlignment="Center"
IsChecked="{Binding IsStarted, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Command="{Binding DataContext.Checked,RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"
CommandParameter="{Binding}"/>
</DataTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding IsStarted}" Value="False">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="Some other template" />
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
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.
Trying to use the same control for displaying a column with images and without, depending on a boolean (HistoryOn). Next xaml code works, but always shows the images.
<DataGridTemplateColumnx:Name="dgtc">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding
Converter={StaticResource myDataRowToListConverter}}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border x:Name="imageBorder" BorderThickness="1" BorderBrush="Black"
MouseLeave="imageBorder_MouseLeave"
MouseEnter="imageBorder_MouseEnter"Height="16">
<Image x:Name="myImage" Source="{BindingMyImagePath}"
MouseUp="Image_MouseUp" HorizontalAlignment="Center">
</Image>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Next xaml code displays only the path, not the images. What is wrong?
<DataGridTemplateColumn x:Name="dgtc">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding
Converter={StaticResource myDataRowToListConverter}}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ContentControl Content="{Binding MyImagePath}">
<ContentControl.Style>
<Style TargetType="ContentControl">
<Style.Triggers>
<DataTrigger Binding="{Binding HistoryOn}" Value="true">
<Setter Property="ContentTemplate"
Value="{StaticResource imagesOff}" />
</DataTrigger>
<DataTrigger Binding="{Binding HistoryOn}" Value="false">
<Setter Property="ContentTemplate"
Value="{StaticResource imagesOn}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
In the Windows.Resources:
<DataTemplate x:Key="imagesOn">
<Border x:Name="imageBorder1" BorderThickness="1" BorderBrush="Black"
MouseLeave="imageBorder_MouseLeave"
MouseEnter="imageBorder_MouseEnter"Height="16">
<Image x:Name="myImage" Source="{BindingMyImagePath}"
MouseUp="Image_MouseUp"HorizontalAlignment="Center">
</Image>
</Border>
</DataTemplate>
<DataTemplatex:Key="imagesOff">
<Border x:Name="imageBorder2" BorderThickness="1" BorderBrush="Black"
MouseLeave="imageBorder_MouseLeave"
MouseEnter="imageBorder_MouseEnter"Height="16">
</Border>
</DataTemplate>
You can use CellTemplateSelector to Choose the desired template depending on the object take a look at this link to see a detailed example on this topic
Good Luck
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