Cannot show quickly list of images in WPF ItemsControl - c#

I have ItemsControl (listbox) with some custom complex data templates. And its take few seconds to show window with this listbox!
My listbox datatemplate contains image:
<Image Stretch="Uniform"
x:Name="image"
Grid.ColumnSpan="1"
Source="{Binding ImagePath}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Width="Auto"
Grid.Column="0"
MinWidth="20"
MinHeight="20"
d:LayoutOverrides="GridBox"
Margin="1,0,1,1" />
Almost all ImagePaths is null. I noticed that this null generates exception but wpf engine hides it! I think this is the source of problem. Is it possible to disable image loading when i know that image path is null!?

Add this DataTrigger to your DataTemplate:
<DataTrigger Binding="{Binding ImagePath}" Value="{x:Null}">
<Setter TargetName="image" Property="Source" Value="{x:Null}"/>
</DataTrigger>

Try FallBackValue attribute which sets a value when binding exception is thrown (msdn link)
eg: FallbackValue="pack://application:,,,/Resources/Images/nocover.png" or {x:null}
There is also TargetNullValue which sets a default value when the bound data is null
Another option would be trying with a converter which returns a default value if parameter is null..
Resolved similar issue here

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>

Xceed Datagrid Cell Colouring

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>

Can binding be used in XAML within a Style?

I wrote a sample to see if binding could be used within a Style in a blank Windows Store app - it compiled but did not work exactly as I'd hoped. I'm relatively new to XAML and binding so may have missed something.
In the sample below there are two rectangles, both bound to the slider control and both should change at the same time as the slider is moved, but it seems that only the first one changes; the first one is bound directly, the second is bound via a style.
Is binding in a Style supposed to be possible in a Win Store app?
(My aim is to have a slider that changes the settings on a large number of elements at once, it seemed like this would be a better approach than copy/pasting bindings to all of them)
<Grid Background="#FF87873D">
<StackPanel>
<StackPanel.Resources>
<Style x:Key="myTestRectangleStyle" TargetType="Rectangle">
<Setter Property="Fill" Value="DarkBlue" />
<Setter Property="Margin" Value="10,10" />
<Setter Property="Height" Value="30" />
<Setter Property="Width" Value="{Binding ElementName=slider1, Path=Value}" />
</Style>
</StackPanel.Resources>
<Rectangle Width="{Binding ElementName=slider1, Path=Value}" Fill="Black" Margin="10,10" Height="30"/>
<Rectangle Style="{StaticResource myTestRectangleStyle}"/>
<Slider Name="slider1" Minimum="20" Maximum="200" Margin="20,0"/>
</StackPanel>
</Grid>
Answering my own question...it seems this isn't possible on a Windows Store App.
I had a clarification from a user on a MSDN forum that
[Bindings] are not supported on Style setters in Windows Store Apps like
they are in WPF, i.e. you cannot bind to the Value property of the
Slider in the Style
So the workaround is just to set the binding directly outside of the Style (a long winded option if you have a lot of elements to bind unfortunately)

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.

Error: The name 'tBox' does not exist in the current context

Error: The name 'tBox' does not exist in the current context.
XAML:
<ItemsControl Name="itemsControl">
<ItemsControl.Template>
<ControlTemplate>
<WrapPenel>
<ItemsPresenter/>
</WrapPenel>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Name="tBox" Text="{Binding Name}"></TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
C#:
tBox.Background=Brushes.White; // Error: The name 'tBox' does not exist in the current context.
How to access control?
The TextBlock you named tBox is inside a DataTemplate. Controls inside a template are in a different name scope, so you can't access it in code-behind via its name. I'm not sure but you might get it via the ItemTemplate property and casting it to a TextBlock. Or you can add a property in your code-behind representing the background and use binding on the TextBlock's Background property. Hope this helps.
Set it on the TextBlock, in your DataTemplate:
<DataTemplate>
<TextBlock Name="tBox" Background="White" Text="{Binding Name}"></TextBlock>
</DataTemplate>
Or if you wish to only set the Background in certain conditions, consider using Triggers:
<DataTemplate>
<TextBlock Name="tBox" Text="{Binding Name}"></TextBlock>
<DataTemplate.Triggers>
<Trigger SourceName="tBox" Property="IsMouseOver" Value="True">
<Setter TargetName="tBox" Property="Background" Value="White" />
</Trigger>
</DataTemplate.Triggers>
</DataTemplate>
More information on how to use Triggers can be found here: A Guided Tour of WPF - Part 4 (Data Templates and Triggers)
I didn't try but maybe the answer here works:
Access a control from within a DataTemplate with its identifying name
to use something like :
var tbUserIcon= (TextBlock)checkBox.Template.FindName("tbUserIcon", checkBox);
But I think this way isn't convenient at all, especially if there's lots of controls have to do it this way, and it can't be checked by intellisense when writing code real time.
this.Background=Brushes.White; (assuming its code behind the control)?
Since Background is a dependency property, you will have to use
tBox.SetValue(BackgroundProperty, new SolidBrush(Color.White));

Categories