When the Image is null, set another default image? - c#

Can you see this tag:
<Image Source="{Binding Image}" Stretch="UniformToFill"/>
But below? What I'm trying to do is, when the Image is null, set another default image. Is this possible?
<!-- Grid-appropriate 250 pixel square item template as seen in the GroupedItemsPage and ItemsPage -->
<DataTemplate x:Key="Standard250x250ItemTemplate">
<Grid HorizontalAlignment="Left" Width="320" Height="240">
<Border Background="{StaticResource ListViewItemPlaceholderRectBrush}">
<Image Source="{Binding Image}" Stretch="UniformToFill"/>
</Border>
<StackPanel VerticalAlignment="Bottom" Background="{StaticResource ListViewItemOverlayBackgroundBrush}">
<TextBlock Text="{Binding ShortTitle}" Foreground="{StaticResource ListViewItemOverlayTextBrush}" Style="{StaticResource TitleTextStyle}" Height="48" Margin="15,0,15,0"/>
</StackPanel>
</Grid>
</DataTemplate>

Add a Style with a DataTrigger. e.g. something like
<Image Stretch="UniformToFill">
<Image.Style>
<Style TargetType="Image">
<Setter Property="Source" Value="{Binding Image}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Image}" Value="{x:Null}">
<Setter Property="Source" Value="Images/Default.png"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
Watch out for precedence of local values.

I'm not sure that you need a trigger I typically use a fallback value like below when I need to specifiy a value when the bound value will not convert.
<Image Source="{Binding Path=ImageURI, FallbackValue='SomeImageURI'}" />
Microsoft FallbackValue Property

Related

Make element visible when Validation.HasError is true

I have the following xaml markup:
<GroupBox Margin="10" Padding="20" Header="Case 5 - Custom Error Object">
<GroupBox.DataContext>
<local:ViewModel4/>
</GroupBox.DataContext>
<StackPanel>
<Label Name="AdornerElement" Style="{StaticResource ResourceKey=AdornerElementStyle}"/>
<TextBox Text="{Binding Path=UserName, UpdateSourceTrigger=PropertyChanged, ValidatesOnNotifyDataErrors=True}"
Margin="0 10"
Validation.ValidationAdornerSite="{Binding ElementName=AdornerElement}">
</TextBox>
</StackPanel>
</GroupBox>
and the following style:
<Style x:Key="AdornerElementStyle" TargetType="Label">
<Setter Property="Visibility" Value="Collapsed"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Label">
<StackPanel Orientation="Horizontal" Background="LightCoral">
<Image Source="/clipart.png" Width="24" Margin="10"/>
<ItemsControl ItemsSource="{Binding ElementName=AdornerElement, Path=(Validation.ValidationAdornerSiteFor).(Validation.Errors)}"
VerticalAlignment="Center">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=ErrorContent.ValidationMessage}"
Style="{StaticResource CustomErrorTypeStyle}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding ElementName=AdornerElement, Path=Validation.HasError}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Everything works fine except Trigger.
If I set up the property "Visibility" to "Visible" initially, then I can see that error messages are shown correctly.
If I use style shown before, then the Label remains to be collapsed.
Please, help me to use triggers correctly to achieve the final result.
This is not how Validation.ValidationAdornerSite works. This attached property just defines the element that will be adorned with the validation error template. By default this is the element that is validating, the Binding.Target to be more precise.
When you set Validation.ValidationAdornerSite the binding engine will automatically set the attached Validation.ValidationAdornerSiteFor property to reference the element that Validation.ValidationAdornerSite was originally set on.
This means that Validation.HasError and other related attached properties are always set on the Binding.Target and not on the adorner site.
That's why your triggers don't work: they are triggering on the Label instead of the TextBox (where the validation/binding error is registered).
To fix it, the DataTrigger must get the Validation.HasErrors attached property value of the Validation.ValidationAdornerSiteFor attached property, which references the original Binding.Target (the TextBox).
<Style x:Key="AdornerElementStyle"
TargetType="Label">
<Setter Property="Visibility"
Value="Collapsed" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Label">
<StackPanel Orientation="Horizontal"
Background="LightCoral">
<Image Source="/clipart.png"
Width="24"
Margin="10" />
<ItemsControl ItemsSource="{Binding ElementName=AdornerElement, Path=(Validation.ValidationAdornerSiteFor).(Validation.Errors)}"
VerticalAlignment="Center">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding ErrorContent.ValidationMessage}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding ElementName=AdornerElement, Path=(Validation.ValidationAdornerSiteFor).(Validation.HasError)}"
Value="True">
<Setter Property="Visibility"
Value="Visible" />
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Remarks
It's not clear why you are using a Label to display the error messages. You could simply define an error template, which is a ControlTemplate that is referenced by the attached Validation.ErrorTemplate property. This would simplify your code significantly.
The following example creates the exact same visual error feedback but without the hassle for an additional Label and associated triggers to manage the visibility of the error messages. All this is all handled by the WPF binding engine.
<Window>
<Window.Resources>
<!-- The Validation.Errors property is the DataContext of this template -->
<ControlTemplate x:Key="ErrorTemplate">
<StackPanel>
<Border BorderBrush="Red"
BorderThickness="1"
Background="LightCoral">
<StackPanel Orientation="Horizontal">
<Image Source="/clipart.png"
Width="24"
Margin="10" />
<ItemsControl ItemsSource="{Binding}"
VerticalAlignment="Center">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding ErrorContent.ValidationMessage}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Border>
<Border BorderBrush="Transparent"
BorderThickness="1"
HorizontalAlignment="Left">
<!-- Placeholder for the Binding.Target -->
<AdornedElementPlaceholder x:Name="AdornedElement" />
</Border>
</StackPanel>
</ControlTemplate>
</Window.Resource>
<StackPanel>
<TextBox Text="{Binding Path=UserName, UpdateSourceTrigger=PropertyChanged, ValidatesOnNotifyDataErrors=True}"
Validation.ErrorTemplate="{StaticResoucre ErrorTemplate}" />
</StackPanel>
</Window>

WPF - Set the same style to multiple controls

Is it possible to set the same style to multiple controls?
I was tried the following way. But 1st Button style was not applied correctly, in second style applied fine.
Design:
<StackPanel Orientation="Horizontal">
<TextBlock Foreground="White" Margin="0,0,5,0">1st Button</TextBlock>
<Button Style="{StaticResource ViewButton}" />
<TextBlock Foreground="White" Margin="25,0,5,0">2nd Button</TextBlock>
<Button Style="{StaticResource ViewButton}" />
</StackPanel>
Resource:
<Style x:Key="ViewButton" TargetType="Button" BasedOn="{StaticResource ButtonStyle}">
<Setter Property="Content">
<Setter.Value>
<StackPanel Orientation="Horizontal">
<Image Source="/Images/View.png" Stretch="None" Width="24" Height="24" />
<TextBlock Margin="5,0,0,0" HorizontalAlignment="Center" VerticalAlignment="Center" FontWeight="Bold">View</TextBlock>
</StackPanel>
</Setter.Value>
</Setter>
<Setter Property="Padding" Value="2,0,10,0"/>
</Style>
You're setting twice the same Content to two different Controls. The problem is that the StackPanel in the Setter.Value can't have two Parents so the last use will be applied. You can use ContentTemplate to make it work:
<Style x:Key="ViewButton" TargetType="Button" BasedOn="{StaticResource ButtonStyle}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="/Images/View.png" Stretch="None" Width="24" Height="24" />
<TextBlock Margin="5,0,0,0" HorizontalAlignment="Center" VerticalAlignment="Center" FontWeight="Bold">View</TextBlock>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="Padding" Value="2,0,10,0"/>
</Style>
....
....
....
You have to mention the TargetType in the as Button. and You need to write the style property following the style name as i wrote.
Hope this will work for You..
thanks

DataGridColumnHeader with StackPanel, bind content of TextBlock/Label to ColumnName, dynamic grid

I have a dynamically generated DataGrid bound to a DataTable property in my ViewModel.
I have AutoGenerateColumnHeaders = true, and it's working fine. However, I'm using a DataTemplate to cover the Header with a StackPanel containing a Label and Button. I cannot seem to figure out how to bind the Label Content to the DataGridColumnHeader. I have tried with and without FindAncestor, but I believe the following is the closest to where I need to be...Question is on the Label Content="{}"
<local:UserControlViewBase.Resources>
<Style TargetType="DataGridColumnHeader">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Border BorderBrush="Black" BorderThickness="1">
<StackPanel Width="Auto" Orientation="Horizontal">
<Label Content="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type local:UserControlViewBase}},Path=DataContext.TestList.ColumnName}" Padding="12,0,12,0" HorizontalAlignment="Center" VerticalAlignment="Center" />
<Button Content="Ok" Padding="12,0,12,0" HorizontalAlignment="Center" VerticalAlignment="Center" />
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</local:UserControlViewBase.Resources>
//local:UserControlViewBase is just a UserControl with some extra bells and whistles added.
I'm fairly new to WPF and I'm assuming I'm just missing something with the binding - I'm still learning.
Thanks.
This is what I did to get it to work. I had to change the findancestor to look for the DataGridColumnHeader instead of the user control. I then was able to access the Column.Header property:
<local:UserControlViewBase.Resources>
<Style TargetType="DataGridColumnHeader">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Border BorderBrush="Black" BorderThickness="1">
<StackPanel Width="Auto" Orientation="Horizontal">
<Label Width="75" Content="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type DataGridColumnHeader}},Path=Column.Header}" Padding="12,0,12,0" HorizontalAlignment="Center" VerticalAlignment="Center" />
<Button Content="Ok" Padding="12,0,12,0" HorizontalAlignment="Center" VerticalAlignment="Center" />
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</local:UserControlViewBase.Resources>

xaml button templates and button over button

I'm struggling with a problem while trying create a collection of buttons.
I have a button made in wpf and when I deploy to my application I want to be able to assign the image at instantiation.
Just now the button textblock is bound to {Binding Content} and I'm able to add the top buttons and an Image placeholder.
What I cant figure out is how to assign the click event handlers to the top two buttons, also when I click the top buttons.
The main button click event fires, I've tried changing the Canvas.ZIndex but that's not working.
I've included a very crude image of what I'm trying to achieve, I could create all the buttons separately but that's not the point, I want one template which will allow me to use over different things.
Is it just a control template I need or do I need a completely new usercontrol developed.
<ControlTemplate x:Key="ButtonTemplate" TargetType="{x:Type Button}">
<Border x:Name="border" BorderThickness="2" CornerRadius="10" Width="200" Height="130" Background="#FF5581A6" RenderTransformOrigin="0.5,0.5">
<StackPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,5,5,0">
<Button Canvas.ZIndex="10">
<StackPanel Orientation="Horizontal">
<Rectangle Width="15" Height="15">
<Rectangle.Fill>
<ImageBrush ImageSource="Resources/Icons/appbar.information.circle.png"/>
</Rectangle.Fill>
</Rectangle>
</StackPanel>
</Button>
<Button x:Name="ClosePlugin" Canvas.ZIndex="10" Margin="5,0,0,0">
<StackPanel Orientation="Horizontal">
<Rectangle Width="15" Height="15">
<Rectangle.Fill>
<ImageBrush ImageSource="Resources/Icons/appbar.close.png"/>
</Rectangle.Fill>
</Rectangle>
</StackPanel>
</Button>
</StackPanel>
<Image x:Name="MainImage" Height="60" Width="80" Margin="0,-5,0,0" Source="{Binding}" Stretch="Fill"/>
<TextBlock FontFamily="Segoe UI" FontWeight="Thin" Margin="0,-5,0,0" FontSize="22" Foreground="White" HorizontalAlignment="Center" VerticalAlignment="Center" x:Name="PluginNameTextBlock" Text="{Binding Content}"/>
</StackPanel>
</Border>
</ControlTemplate>
In my applications I use this solution.
I have defined attached property ImgSource in class ButtonBehavior:
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
namespace WpfStackOverflowSample
{
public static class ButtonBehavior
{
private static readonly DependencyProperty ImgSourceProperty = DependencyProperty.RegisterAttached(
"ImgSource",
typeof (ImageSource),
typeof (ButtonBehavior),
new PropertyMetadata(default(ImageSource)));
public static void SetImgSource(ButtonBase button, ImageSource value)
{
button.SetValue(ImgSourceProperty, value);
}
public static ImageSource GetImgSource(ButtonBase button)
{
return (ImageSource)button.GetValue(ImgSourceProperty);
}
}
}
Then I define ContentTemplate for "ImageButtons" and finally when I want to use this kind of buttons I just set attached property ImgSource a apply style with the ContentTemplate
<Window x:Class="WpfStackOverflowSample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfStackOverflowSample"
Title="MainWindow" Height="480" Width="640">
<Window.Resources>
<Style TargetType="{x:Type ButtonBase}">
<Setter Property="Margin" Value="0,5" />
<Setter Property="MinWidth" Value="100" />
<Setter Property="HorizontalAlignment" Value="Center" />
</Style>
<Style x:Key="ImgButtonStyle" TargetType="{x:Type ButtonBase}" BasedOn="{StaticResource {x:Type ButtonBase}}">
<Setter Property="local:ButtonBehavior.ImgSource" Value="/Images/unknown.png" />
<Setter Property="Padding" Value="2" />
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image
x:Name="img"
Source="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Button}}, Path=(local:ButtonBehavior.ImgSource)}"
Stretch="UniformToFill"
Width="16" Height="16"
Margin="0,0,5,0" />
<TextBlock
x:Name="txt"
Text="{Binding}"
VerticalAlignment="Center" />
</StackPanel>
<DataTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="img" Property="Opacity" Value="0.3" />
<Setter TargetName="txt" Property="Foreground" Value="#ADADAD"></Setter>
</Trigger>
</DataTemplate.Triggers>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type ButtonBase}}" />
</Window.Resources>
<StackPanel Orientation="Vertical" VerticalAlignment="Center">
<Button local:ButtonBehavior.ImgSource="/Images/encrypt.png"
Style="{StaticResource ImgButtonStyle}"
Content="Encrypt" />
<Button local:ButtonBehavior.ImgSource="/Images/decrypt.png"
Style="{StaticResource ImgButtonStyle}"
Content="Decrypt"
IsEnabled="False" />
<Button Style="{StaticResource ImgButtonStyle}"
Content="No image" />
<Button Content="Classic" />
<Button Content="Classic"
IsEnabled="False" />
</StackPanel>
</Window>

Backgroundcolor of entire ToolTip

Does anyone know a simple XAML solution to change the entire background of a ToolTip?
I did the following:
<Image Height="16" Source="Images/Icons/Add2.png" Stretch="Fill" Width="16" Opacity="0.99" Grid.Column="0">
<Image.ToolTip>
<Grid Background="#000000">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Text="Header1" FontSize="15" Grid.Row="0"/>
<TextBlock Text="Subitem" FontSize="12" Grid.Row="1"/>
</Grid>
</Image.ToolTip>
</Image>
But the result looks like that:
Any suggestions?
The problem is that all you're really doing is setting the CONTENT of the tooltip, not the tooltip itself.
So you'll need to style the tooltip to make this happen. There are some ways to do it with resources as seen in this post:
WPF- Changing Tooltip background to Transparent
or you can change your code to wrap that grid with an explicit ToolTip and set its background property:
<Image.ToolTip>
<ToolTip Background="Black">
<Grid>
...
</Grid>
</ToolTip>
</Image.ToolTip>
To set the tooltip background you can override the style of the tooltip for the parent control. Below is your code with added style.
<Image Height="16" Source="Images/Icons/Add2.png" Stretch="Fill" Width="16" Opacity="0.99" Grid.Column="0">
<Image.Resources>
<Style TargetType="ToolTip" BasedOn="{StaticResource {x:Type ToolTip}}">
<Setter Property="Background" Value="#000000" />
</Style>
</Image.Resources>
<Image.ToolTip>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Text="Header1" FontSize="15" Grid.Row="0"/>
<TextBlock Text="Subitem" FontSize="12" Grid.Row="1"/>
</Grid>
</Image.ToolTip>
</Image>
To change or Set the Background/Foreground color for the Tooltip in DataGrid in WPF
Create the DataGrid as "Grid1" and add the DataGridTextColumn which contains the ToolTip with item.
To change the Background colour for the ToolTip, add the Setter property in the DataGrid Resources
<DataGrid x:Name="Grid1">
<DataGrid.Resources>
<Style TargetType="ToolTip">
<Setter Property="Background" Value="Black"></Setter>
<Setter Property="Foreground" Value="White"></Setter>
</Style>
</DataGrid.Resources>
<DataGridTextColumn Header="ActionName" Binding={Binding ActionName}>
<DataGridTextColumn.CellStyle>
<Setter Property="Control.ToolTip">
<Setter.Value>
<UniformGrid Columns="1">
<TextBlock Text="Action List" FontWeight="Bold"/>
<TextBlock Text="Cut"/>
<TextBlock Text="Copy"/>
<TextBlock Text="Delete"/>
</UniformGrid>
</Setter.Value>
</Setter>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
</DataGrid>

Categories

Resources