Xceed Datagrid Cell Colouring - c#

I have an xceed WPF Datagrid that I want to color a particular cell in each row a particular way.
The grid is bound to a Collection of Bid objects. The column I want to apply to color is BidValue.
<xcdg:DataGridCollectionViewSource x:Key="BidViewSource" Source="{Binding Bids}"
d:DesignSource="{d:DesignInstance {x:Type models:Bid}, CreateList=True}">...
<xcdg:DataGridControl Name="BidGrid" DockPanel.Dock="Bottom" VerticalAlignment="Top" AutoCreateColumns="False"
ReadOnly="True" ItemsSource="{Binding Source={StaticResource BidViewSource}}"...
In order to simply the process, Bid.BackgroundColor and Bid.ForegroundColor exist for the purpose of supplying getters that determine the correct Color that BidValue should be displayed in.
Basically what I'm trying to do should begin something like this:
<xcdg:Column FieldName="BidValue" Title="Bid" CellHorizontalContentAlignment="Center" MaxWidth="75" AllowSort="False">
<xcdg:Column.CellContentTemplate>
<DataTemplate>
<DataTemplate.Triggers>
The remaining part that connects it to my the color fields in the Bid object is proving difficult. I've tried to implement the coloring logic in XAML (which is more common) with something like this:
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=BidValue}" Value="X" >
<Setter Property="Background" Value="Red"/>
<Setter Property="Foreground" Value="White"/>
</DataTrigger>
but when I do I get the following:
error MC4109: Cannot find the Template Property 'Background' on the type 'System.Windows.Controls.ContentPresenter

This code actually gets the data from one column (BidText) to use set the Color of another (BidValue) column -- which is its own mean feat using xceed DataGrids.
As alluded to above, a control (a textblock in this case) has to be set in the column's template and bound to the data that was already being displayed. The XAML for referring to another xceed Datagrid column's content to pass into the ColorConverter is shown in the Background and Foreground property assignments. That reference column doesn't need to be visible as is done here, with the Visibility property set to False.
<xcdg:Column FieldName="BidText" Visible="False" AllowSort="False"/>
<xcdg:Column FieldName="BidValue" Title="Bid" CellHorizontalContentAlignment="Center" MaxWidth="50" AllowSort="False">
<xcdg:Column.CellContentTemplate>
<DataTemplate>
<TextBlock Name="TextBlock" Width="50" HorizontalAlignment="Stretch" VerticalAlignment="Top" TextAlignment="Center"
Text="{Binding}" FontWeight="Bold"
Foreground="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type xcdg:Cell}}, Path=ParentRow.DataContext.BidText, Converter={StaticResource FGColorConverter}}"
Background="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type xcdg:Cell}}, Path=ParentRow.DataContext.BidText, Converter={StaticResource BGColorConverter}}"/>
</DataTemplate>
</xcdg:Column.CellContentTemplate>
</xcdg:Column>

Related

ToolTipService.ToolTip not working on DataGridCell in UWP XAML

i'm trying to display a tooltip over a cell in a Windows Toolkit DataGrid in UWP XAML.
I'm able to show a static value by doing this:
<wct:DataGridTextColumn Width="200" Binding="{Binding ChargeInformationDto.Description, Mode=OneWay}" Header="Navn" Tag="Description">
<wct:DataGridTextColumn.CellStyle>
<Style TargetType="wct:DataGridCell">
<Setter Property="ToolTipService.ToolTip" Value="Tooltip text to show" />
</Style>
</wct:DataGridTextColumn.CellStyle>
</wct:DataGridTextColumn>
But with Bindings it does not show:
<wct:DataGridTextColumn Width="200" Binding="{Binding ChargeInformationDto.Description, Mode=OneWay}" Header="Navn" Tag="Description">
<wct:DataGridTextColumn.CellStyle>
<Style TargetType="wct:DataGridCell">
<Setter Property="ToolTipService.ToolTip" Value="{Binding ChargeInformationDto.Description, Mode=OneWay}" />
</Style>
</wct:DataGridTextColumn.CellStyle>
</wct:DataGridTextColumn>
Anyone managed to make this work?
In UWP XAML, you cannot use binding in Style. For specific instructions, please refer to this document:
Windows Presentation Foundation (WPF) and Microsoft Silverlight supported the ability to use a Binding expression to supply the Value for a Setter in a Style. The Windows Runtime doesn't support a Binding usage for Setter.Value (the Binding won't evaluate and the Setter has no effect, you won't get errors, but you won't get the desired result either).
As you can see in the source code of DataGridTextColumn, DataGridTextColumn will dynamically create a TextBlock and TextBox to display and edit content, so using TooltipService directly in the XAML to set Tooltip will not be attached to the newly created TextBlock, which is the reason of Tooltip cannot be displayed.
If you want to display Tooltip, then you can consider creating a DataGridTemplateColumn:
<controls:DataGridTemplateColumn Width="200"
Header="Navn" Tag="Description">
<controls:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding ChargeInformationDto.Description, Mode=OneWay}" FontSize="20"
ToolTipService.ToolTip="{Binding ChargeInformationDto.Description, Mode=OneWay}"/>
</DataTemplate>
</controls:DataGridTemplateColumn.CellTemplate>
</controls:DataGridTemplateColumn>

Two way binding of IsChecked within a nested MenuItem

I have a nested context menu like this:
<ContextMenu DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Thing Count" ItemsSource="{Binding ThingsProvider}">
NB the Thing Count parent MenuItem with children from ThingsProvider.
ThingsProvider provides a List of ThingViewModel which contains properties Thing and IsChecked. I want to be able to control IsChecked from my main view model and from the user via the MenuItem but I have hit a problem; If I use an ItemContainerStyle like this.
<MenuItem.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="Header" Value="{Binding Path=Thing, Mode=OneWay}"/>
<Setter Property="IsChecked" Value="{Binding Path=IsChecked, UpdateSourceTrigger=PropertyChanged}"/>
</Style>
</MenuItem.ItemContainerStyle>
then (predictably I suppose as it's a style) it will observe the ViewModel's IsChecked but will not set it.
If I use an ItemTemplate like so
<MenuItem.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Thing, Mode=OneWay}"/>
</DataTemplate>
</MenuItem.ItemTemplate>
I can't get to the MenuItem's IsChecked property as I've only got the TextBlock. If I put a MenuItem in the ItemTemplate then I end up with nested MenuItems in my UI and it looks bad.
There must be a way to do this but I'm stumped at the moment, can anyone help?
Cheers
Rich

Updating Values in the Control Template of the ComboBox

I implemented a column in a data grid that containes comboboxes. In order to display a text box in stead of a combobox when a list containes only one value, I used the solution from this post:
How to hide combobox toggle button if there is only one item?
However, when that one value in the list is changed, it is not updated in the text box. I have, of course, implemented INotifyPropertyChanged and it works as long as I have more than one item in the list (in other words, when the combobox is shown) but the value in the TextBlock is never updated.
Edit:
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox Name="CList" ItemsSource="{Binding Values, UpdateSourceTrigger=PropertyChanged}"
SelectedItem="{Binding Path=SelectedValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
SelectedIndex="0" BorderBrush="Transparent"
Background="Transparent">
<ComboBox.Style>
<Style TargetType="{x:Type ComboBox}" >
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Items.Count, ElementName=CList}" Value="1">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<TextBlock Text="{Binding Items[0], ElementName=CList}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ComboBox.Style>
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
I can see you are binding to the item itself, instead of any property in it
so perhaps you many need to bind to the respective property of your data item
eg
<TextBlock Text="{Binding Items[0].MyProperty, ElementName=CList}" />
assuming your intended property is MyProperty
Note if there is no underlying property then you'll have to remove the item and add new one again to list in order to update the text block, in this scenario INotifyPropertyChanged will also not work

Hide tooltip if binding is null

Currently i've got the following code to show a tooltip.
<Border BorderBrush="Black"
BorderThickness="{Binding Border}"
Height="23"
Background="{Binding Color}">
<ToolTipService.ToolTip>
<TextBlock Text="{Binding TooltipInformation}" />
</ToolTipService.ToolTip>
This is presented in a ItemsControl with about 25 items. Only a few of these have a value set to TooltipInformation
If TooltipInforation is an empty string, it still shows the tooltipbox containing the textblock as a very small window (about 5px high and 20px wide). Even if I set the textblock visbility to collapsed.
Is there a way to completely remove the tooltip if the value of TooltipInformation is null or a empty string?
One way to hide an empty tooltip for all controls is to create a style in a resource dictionary that is included in your App.xaml.
This style sets the visibility to collapsed when the tooltip is an empty string or null:
<!-- Style to hide tool tips that have an empty content. -->
<Style TargetType="ToolTip">
<Style.Triggers>
<Trigger Property="Content"
Value="{x:Static sys:String.Empty}">
<Setter Property="Visibility"
Value="Collapsed" />
</Trigger>
<Trigger Property="Content"
Value="{x:Null}">
<Setter Property="Visibility"
Value="Collapsed" />
</Trigger>
</Style.Triggers>
</Style>
Also include sys namespace (for String.Empty):
xmlns:sys="clr-namespace:System;assembly=mscorlib"
One way you can do that is wrap the ToolTip in a Rectangle and give it a Transparent color. Then you just set the Visibility to Collapsed on this Rectangle.
Update:
<Border Background="#FFE45F5F">
<Grid>
<TextBlock Text="{Binding Property1}"/>
<Rectangle Fill="Transparent" Visibility="{Binding Property2, Converter={StaticResource BooleanToVisibilityConverter}}" ToolTipService.ToolTip="{Binding TooltipInformation}"/>
</Grid>
</Border>
This is a WPF answer (haven't tried it in Silverlight).
Use ToolTipService.IsEnabled, and bind it to the tooltip property. Then use a converter to convert the tooltip string to a bool.
For example, I have the following:
<TextBlock x:Name="textBlock" ToolTipService.IsEnabled="{Binding EntryToolTip, Converter={StaticResource StringNullOrEmptyToBoolConverter}}">
...
</TextBlock>
Or in code-behind
ToolTipService.SetIsEnabled(textBlock, false);
I was having the same issue as I was setting value to String.Empty. Setting it to null solves the problem.
WinRT/Windows 8 App XAML
If just using the default tooltip I would otherwise recommend either setting the bound value to null in the viewmodel or using a converter whenever the item is empty.
In my case I've got a:
public string Name { get; }
Bound using:
<TextBlock Text="{Binding Name}" TextTrimming="CharacterEllipsis" Tooltip="{Binding Name}" />
Where the idea is to show the full name in the tooltip if cut of due to lack of width. In my viewmodel I simply:
if (string.IsNullOrEmpty(Name)) Name = null;
At least in .Net 4.0 this will not show a tooltip for me.
Strangely, none of these answers worked in my case. A reply to the top answer alludes to it - if you're ToolTip is related to a TextBlock then that solution won't work. I have a TextBlock within a DataGridTemplateColumn.CellTemplate element, and I just bound the text directly to the ToolTip property of the TextBlock like this:
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
ToolTip="{Binding Path=SomeTextProperty}"
Style="{StaticResource TextBlockOverflowStyle}"
Text="{Binding Path=SomeTextProperty, NotifyOnSourceUpdated=True}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
And I ended up getting the desired behavior (hidden tooltip when text is empty) "for free".
You could create a converter from string to bool that returns false if the string length is 0 and true otherwise, then bind ToolTip.Active to TooltipInformation with that converter.

Showing SelectedItem Details to its side

I've a ListView bound to an ObservableCollection<Foo>. On selecting a ListViewItem I display the details of the SelectedItem(Foo members) in a container. It works fine.
Now all I want is to display the details just next to the SelectedItem. ie, If I select the fourth ListViewItem then the Container's Top should be the same as the ListViewItem's Top. How would I sync their position provided it should create any problem even while scrolling the List.
P.S: Scrollbars are hidden
This question is not yet resolved. Can anybody help?
Original Answer
Does the detail need to be in a separate container? I may be misunderstanding your example, but I would have thought you could achieve what you wanted by adding the details section to the item template for your list items and then hiding/showing it based on the IsSelected flag:
<ListView ItemsSource="{Binding}">
<ListView.ItemTemplate>
<DataTemplate>
<DockPanel>
<ContentControl DockPanel.Dock="Right" Name="DetailsControl" Content="{Binding}" ContentTemplate="{StaticResource DetailsTemplate}" />
<TextBlock Text="{Binding}" />
</DockPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding (ListViewItem.IsSelected), RelativeSource={RelativeSource FindAncestor, AncestorType=ListViewItem}}" Value="False">
<Setter TargetName="DetailsControl" Property="Visibility" Value="Hidden" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Even if you aren't after exactly this behaviour, I imagine you could get close to what you want by replacing the ContentControl from the example with something else (e.g. a Popup)
Edit in response to comments
The example below will place a Popup to the right hand side of the ListView that is visible only for the selected item:
<ListView ItemsSource="{Binding}">
<ListView.ItemTemplate>
<DataTemplate>
<DockPanel>
<TextBlock Text="{Binding}" />
<Popup Placement="Right"
PlacementTarget="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ListViewItem}}"
IsOpen="{Binding (ListViewItem.IsSelected), RelativeSource={RelativeSource FindAncestor, AncestorType=ListViewItem}}">
<Border Background="Black" Padding="3">
<TextBlock Text="{Binding}" />
</Border>
</Popup>
</DockPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
This uses the Placement attribute to specify that the Popup should appear to the right of the target element, and binds the PlacementTarget property to the first ancestor of type ListViewItem (i.e. the parent container).
This causes an appearance like the example below:

Categories