Trying to pass validation to my custom tooltip control - wpf

I am trying to make a custom tooltip control that is used for TextBoxes.
It will look like this:
...except for some pixels that comes from the background components that I have gimped away as good as possible.
The idea comes from:
How to implement Balloon message in a WPF application
The problem is that the code behind of my custom control never gets the validation object (that should be passed to it via the trigger in generic.xaml).
Why not?
generic.xaml:
<Style TargetType="{x:Type TextBox}" x:Name="tb">
<Setter Property="Width" Value="200" />
<Setter Property="Background" Value="{StaticResource InputBackgroundColor}" />
<Setter Property="BorderBrush" Value="{StaticResource InputBorderBrush}" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="Margin" Value="5,0,0,5" />
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip">
<Setter.Value>
<Windows:ValidationBalloonPopupWindow
Validation="{Binding Path=Validation, ElementName=tb}" />
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
As you see, I try to refer to Validation by using ElementName of tb.
Seems like Name is not used in templates. If I change to x:Key instead, all my textboxes becomes like 10 pixels wide. Probably not the right thing to do in other words.
The code behind, ValidationBalloonPopupWindow.xaml.cs:
using System.Windows;
using System.Windows.Controls;
namespace Foo.ToolTips
{
public partial class ValidationBalloonPopupWindow : ToolTip
{
public ValidationBalloonPopupWindow()
{
InitializeComponent();
}
public static DependencyProperty ValidationProperty
= DependencyProperty.Register("Validation", typeof(object), typeof(ValidationBalloonPopupWindow),
new PropertyMetadata(null, OnChangedValidationByBinding));
private static void OnChangedValidationByBinding
(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((ValidationBalloonPopupWindow)d).OnChangedValidationByBinding(e.NewValue);
}
public void OnChangedValidationByBinding(object newValue)
{
txtMessage.Text = newValue.GetType().Name;
}
private object _validation;
public object Validation
{
get
{
return _validation;
}
set
{
_validation = value;
txtMessage.Text = _validation.GetType().Name;
}
}
}
}
Which has a setter that should run, I have tried to put a lot of breakpoints in this file without success.
The xaml for the control itself, ValidationBalloonPopupWindow.xaml:
<ToolTip x:Class="FRAM.Windows.ValidationBalloonPopupWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Background="Transparent" BorderBrush="Transparent" HasDropShadow="false"
Placement="Bottom"
Height="Auto" Width="Auto">
<Grid Height="126" Width="453">
<Border Margin="7,13,0,0"
CornerRadius="10,10,10,10" Grid.ColumnSpan="4" HorizontalAlignment="Left" Width="429" Height="82" VerticalAlignment="Top" Grid.RowSpan="2">
<Border.Effect>
<DropShadowEffect Color="#FF474747" />
</Border.Effect>
<Border.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF58C2FF" Offset="0" />
<GradientStop Color="#FFFFFFFF" Offset="1" />
</LinearGradientBrush>
</Border.Background>
<StackPanel Orientation="Vertical">
<Label Content="Title" Height="31" HorizontalAlignment="Left"
Margin="12,8,0,0" Name="lblCaption" FontSize="16" FontWeight="Bold" />
<TextBlock Margin="18,0,0,0" Name="txtMessage" Width="378" HorizontalAlignment="Left">Body</TextBlock>
</StackPanel>
</Border>
<Path Data="M25,25L10.9919,0.64 0.7,25" Fill="#FF58C2FF" HorizontalAlignment="Left"
Margin="32,3,0,0" Stretch="Fill" Width="22" Height="10" VerticalAlignment="Top" />
</Grid>
</ToolTip>

Instead of referring by name, get the Textbox itself by using RelativeSource binding.
Try something like this:
<Setter Property="ToolTip">
<Setter.Value>
<Windows:ValidationBalloonPopupWindow
Validation="{Binding RelativeSource={RelativeSource Self}, Path=Validation}" />
</Setter.Value>
</Setter>

Related

DataTrigger referencing an enum DependencyProperty

Solution: Please look at Ilan answer!
I am currently working on some CustomControls and this is one of them. Depending on the DirectionProperty i want to change the direction of the linearGradientBrush with the DataTrigger. I am not really able to get it working and hope for your help.
It looks like the DataTrigger isn't really able to get the Value or the Direction. Thanks in advance
SanHolo
EDIT: Doing it like that i get an error:
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='CustomControlLibrary.ColoredProgress', AncestorLevel='1''. BindingExpression:Path=Direction; DataItem=null; target element is 'ColoredProgress' (Name=''); target property is 'NoTarget' (type 'Object')
C#
using System.Windows;
using System.Windows.Controls;
namespace CustomControlLibrary
{
public class ColoredProgress : Control
{
public enum colorDirection { Increase, Decrease }
private static DependencyProperty ProgressProperty =
DependencyProperty.Register("Progress", typeof(double), typeof(ColoredProgress), new PropertyMetadata(0.00));
private static DependencyProperty DirectionProperty =
DependencyProperty.Register("Direction", typeof(colorDirection), typeof(ColoredProgress), new PropertyMetadata(colorDirection.Increase));
public double Progress
{
get { return (double)GetValue(ProgressProperty); }
set { SetValue(ProgressProperty, converter(value)); }
}
public colorDirection Direction
{
get { return (colorDirection)GetValue(DirectionProperty); }
set { SetValue(DirectionProperty, value); }
}
public ColoredProgress()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ColoredProgress), new FrameworkPropertyMetadata(typeof(ColoredProgress)));
this.Loaded += ColoredProgress_Loaded;
}
private void ColoredProgress_Loaded(object sender, RoutedEventArgs e)
{
double height = (double)GetValue(ColoredProgress.ActualHeightProperty);
SetValue(ProgressProperty, height - (height * Progress));
}
//takes a double between 0-1 (percent of the ProgressBar) and converts it to the value needed in the design
private double converter(double percentage)
{
double height = (double)GetValue(ColoredProgress.ActualHeightProperty);
return height - (height * percentage);
}
}
}
XAML
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CustomControlLibrary">
<Style TargetType="{x:Type local:ColoredProgress}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:ColoredProgress}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
RenderTransformOrigin="0.5, 0.5"
DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:ColoredProgress}}}">
<Grid x:Name="PART_Bar">
<Grid Background="Transparent" Panel.ZIndex="1">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Rectangle Fill="{TemplateBinding Background}" Height="{Binding Path=Progress, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</Grid>
<Grid Panel.ZIndex="0">
<Grid.RowDefinitions>
<RowDefinition Height="*" x:Name="increase"/>
<RowDefinition Height="0" x:Name="decrease"/>
</Grid.RowDefinitions>
<Rectangle Grid.Row="0">
<Rectangle.Fill>
<LinearGradientBrush StartPoint="0.5,1" EndPoint="0.5,0">
<GradientStop Color="Yellow" Offset="0.0" />
<GradientStop Color="Red" Offset="1.0" />
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<Rectangle Grid.Row="1">
<Rectangle.Fill>
<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
<GradientStop Color="Yellow" Offset="0.0" />
<GradientStop Color="Red" Offset="1.0" />
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
</Grid>
</Grid>
</Border>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding Path=Direction, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:ColoredProgress}}}" Value="colorDirection.Decrease">
<Setter TargetName="increase" Property="Height" Value="0"/>
<Setter TargetName="decrease" Property="Height" Value="*"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
please use the regular triggers:
<ControlTemplate TargetType="{x:Type local:ColoredProgress}">
...
<ControlTemplate.Triggers>
<Trigger Property="Direction" Value="Decrease">
<Setter TargetName="increase" Property="Height" Value="0"/>
<Setter TargetName="decrease" Property="Height" Value="*"/>
</Trigger>
<Trigger Property="Direction" Value="Increase">
<Setter TargetName="increase" Property="Height" Value="*"/>
<Setter TargetName="decrease" Property="Height" Value="0"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
As I understand the data trigger go to the DataContext to check for the value, since you've defined a Direction as a dependency property of your control you, can get the value directly. More over you can't point the data context because you haven't any property in you data context that can provide you with the value you need. That is why you get the binding expression error.
Let me know if you need more explanation.
Regards.
I haven't run your code, but I suppose your problem is that your value binding in the DataTrigger is not set correctly to the Enum value you expect.
Try this: (Note the new Value binding)
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding Path=Direction, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:ColoredProgress}}}"
Value="{x:Static local:colorDirection.Decrease}">
<Setter TargetName="increase" Property="Height" Value="0"/>
<Setter TargetName="decrease" Property="Height" Value="*"/>
</DataTrigger>
</ControlTemplate.Triggers>
I suppose it should work, but I didn't check the rest of the code, so feel free to update your progress in here.

how to bind collection to custom control in wpf

I am building a custom control and I want to pass a collection to it so that control display that collection, my code is as the following :
<gm:Calendar SubscriptionSource="{Binding Subscriptions}"></gm:Calendar>
and in Custom control "Calendar"
public static readonly DependencyProperty SubscriptionSourceProperty =
DependencyProperty.Register(
"SubscriptionSource",
typeof(ObservableCollection<Subscription>),
typeof(Calendar),
new FrameworkPropertyMetadata(new ObservableCollection<Subscription>()));
public ObservableCollection<Subscription> SubscriptionSource
{
get
{
return (ObservableCollection<Subscription>)GetValue(SubscriptionSourceProperty);
}
set
{
SetValue(SubscriptionSourceProperty, value);
}
}
I use in generic.xaml
<ItemsControl ItemsSource="{Binding SubscriptionSource}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<!--Box-->
<Border BorderBrush="Black" BorderThickness="1" Padding="0">
<Border Name="InnerBorder" BorderBrush="{Binding Path=Day, Converter={StaticResource DayBorderColorConverter}}" BorderThickness="2">
<Border.Style>
<Style TargetType="{x:Type Border}">
<Style.Triggers>
<!--Current Day-->
<DataTrigger Binding="{Binding IsToday}" Value="true">
<Setter Property="Border.Background">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF1EA6C8" Offset="0"/>
<GradientStop Color="#FF0691B3" Offset="1"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<DockPanel>
<!--Day Number-->
<StackPanel Orientation="Horizontal" DockPanel.Dock="Top" FlowDirection="RightToLeft">
<TextBlock TextAlignment="Right" Text="{Binding Day.Date, Converter={StaticResource DateConverter}, ConverterParameter=DAY}" FontSize="12" Margin="5,5,5,5" >
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsTargetMonth}" Value="false">
<Setter Property="TextBlock.Foreground" Value="Gray"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</StackPanel>
<CheckBox IsEnabled="{Binding IsEnabled}" Style="{StaticResource DiscreteCheckBoxStyle}" />
</DockPanel>
</Border>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="6" Columns="7" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
I want to Bind Subscriptions observable collection to the calendar custom control so I can use the collection in the custom control, is there is away to do this?
If the ItemsControl is inside the ControlTemplate, then Change the {Binding SubscriptionSource} for {TemplateBinding SubscriptionSource}
My problem is now Solved thanks to #Luke Woodward and I just had another problem that I use the custom control inside usercontrol and that usercontrol was an item inside ListItem
I modified the binding expression
<gm:Calendar SubscriptionSource="{Binding Path=Subscriptions,Mode=TwoWay}" >
and the customcontrol is
static Calendar()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(Calendar), new FrameworkPropertyMetadata(typeof(Calendar)));
}
public ObservableCollection<SubscriptionDay> SubscriptionSource
{
get { return (ObservableCollection<SubscriptionDay>)GetValue(SubscriptionSourceProperty); }
set { SetValue(SubscriptionSourceProperty, value); }
}
public static readonly DependencyProperty SubscriptionSourceProperty =
DependencyProperty.Register("SubscriptionSource", typeof(ObservableCollection<SubscriptionDay>), typeof(Calendar), new FrameworkPropertyMetadata(new ObservableCollection<SubscriptionDay>()));
and in the Generic.xaml modified as #HighCore posted
<ItemsControl ItemsSource="{TemplateBinding SubscriptionSource}">
<ItemsControl.ItemTemplate>
<DataTemplate>......
and finally worked.
Thanks to #Luke Woodward and #HighCore

XAML image source set dynamically based on content

Well it's not really very dynamic, at least it won't change at runtime.
The idea is I have buttons and each one has a unique image ( icon 32x32 ). The buttons all share a style where I mess with the ControlTemplate. So each image also has 2 colors one normal and another when I mouse over.
I noticed that when I declare the source path for the images is that they are almost all the same so I though DRY ( Don't Repeat Yourself ). What if I could use the button Name or some other property as part of the source path ( i.e. the name of the image file ). That would be good programming.
Problem is I'm new to XAML, WPF and perhaps programming all together so I'm not sure how to do that. I guess this would need code behind or a converter of some sort ( guess I'll read about converters a bit more ). Here is a bit of code ( this doesn't work but it gives you the general idea ( hopefully )):
<Style x:Key="ButtonPanelBigButton" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Name="ButtonBorder"
Height="78"
MaxWidth="70"
MinWidth="50"
BorderThickness="0.5"
BorderBrush="Transparent"
CornerRadius="8" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="2*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- Here I wan't to put in the Name property of the button because there is a picture there to match -->
<Image x:Name="ButtonIcon" Source="..\Images\Icons\32x32\Blue\{Binding Name}.png"
Margin="4"
Height="32"
Width="32"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
<TextBlock Grid.Row="1"
Padding="5,2,5,2"
TextWrapping="Wrap"
Style="{StaticResource MenuText}"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<ContentPresenter ContentSource="Content" />
</TextBlock>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True" >
<Setter TargetName="ButtonIcon" Property="Source" Value="..\Images\Icons\32x32\Green\user.png" /> <!-- Same Here -->
<Setter TargetName="ButtonBorder" Property="BorderBrush" Value="{StaticResource SecondColorBrush}" />
<Setter TargetName="ButtonBorder" Property="Background">
<Setter.Value>
<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1" Opacity="0.5">
<GradientStop Color="{StaticResource MainColor}" Offset="1" />
<GradientStop Color="{StaticResource SecondColor}" Offset="0.5" />
<GradientStop Color="{StaticResource MainColor}" Offset="0" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Hopefully you get where I'm going with this and someone might be able to help me so my code is nice and DRY ( now I'M repeating myself!!! ).
You're right: The easy way to solve this is to use a converter.
The Source property takes an ImageSource, so you'll need to load the bitmap yourself in your converter.
The converter is used like this:
<Image Source="{Binding Name,
RelativeSource={RelativeSource TemplatedParent},
Converter={x:Static local:ImageSourceLoader.Instance},
ConverterParameter=..\Images\Icons\32x32\Blue\{0}.png}" />
And implemented like this:
public class ImageSourceLoader : IValueConverter
{
public static ImageSourceLoader Instance = new ImageSourceLoader();
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var path = string.Format((string)parameter, value.ToString());
return BitmapFrame.Create(new Uri(path, UriKind.RelativeOrAbsolute));
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Note that this simple solution can't handle relative Uris because the BaseUri property of the Image is unavailable to the converter. If you want to use relative Uris, you can do this by binding an attached property and using StringFormat:
<Image local:ImageHelper.SourcePath="{Binding Name,
RelativeSource={RelativeSource TemplatedParent},
StringFormat=..\Images\Icons\32x32\Blue\{0}.png}" />
And the attached property's PropertyChangedCallback handles loads the image after combining the BaseUri with the formatted Uri string:
public class ImageHelper : DependencyObject
{
public static string GetSourcePath(DependencyObject obj) { return (string)obj.GetValue(SourcePathProperty); }
public static void SetSourcePath(DependencyObject obj, string value) { obj.SetValue(SourcePathProperty, value); }
public static readonly DependencyProperty SourcePathProperty = DependencyProperty.RegisterAttached("SourcePath", typeof(string), typeof(ImageHelper), new PropertyMetadata
{
PropertyChangedCallback = (obj, e) =>
{
((Image)obj).Source =
BitmapFrame.Create(new Uri(((IUriContext)obj).BaseUri, (string)e.NewValue));
}
});
}
You can use the Tag Property and set the full path of the image in Tag and then use it.
the following my code to be more clear
*<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="#373737" />
<Setter Property="Foreground" Value="White" />
<Setter Property="FontSize" Value="12" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border CornerRadius="7" Background="{TemplateBinding Background}" FlowDirection="RightToLeft">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="2"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image x:Name="imgDistance" Source="{Binding Tag,RelativeSource={RelativeSource TemplatedParent}}"
Width="35" Height="35" HorizontalAlignment="Left" Margin="42,7,0,8" Grid.Column="0"/>*
and then I used it in the button as following
<Button x:Name="btnDistance" Height="50" VerticalAlignment="Top" Margin="0,4,0,0" Curs
or="Hand" Click="btnDistance_Click" Tag="/Images/distance.png">

Display image in content presenter in button

I have a button with a style that displays an image inside it. I would like to be able to specify the image it uses using the Content property on the button (or some other means).
How can accomplish this without actually nesting an image directly in the button.
<BitmapImage x:Key="closeImage" UriSource="close.png" />
I thought I could maybe specify the image file name like so:
<Button Content="{{StaticResource closeImage}" x:Name="closeButton" Click="closeButton_Click" Style="{DynamicResource WindowToolboxButton}"/>
Style:
<Style x:Key="WindowToolboxButton" TargetType="{x:Type Button}">
<Setter Property="FocusVisualStyle" Value="{StaticResource ButtonFocusVisual}"/>
<Setter Property="Background" Value="{StaticResource ButtonNormalBackgroundFill}"/>
<Setter Property="BorderBrush" Value="{StaticResource ButtonBorder}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid x:Name="grid" Height="15" Width="15">
<Border x:Name="border" CornerRadius="2,2,2,2" BorderBrush="#FFBBCDD2" BorderThickness="1" Opacity="0" Margin="0">
<Border.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF82A3AC" Offset="1"/>
<GradientStop Color="#7FCDD9DC"/>
</LinearGradientBrush>
</Border.Background>
</Border>
<Image x:Name="image" Source="close.png" Stretch="None" VerticalAlignment="Center" HorizontalAlignment="Center" >
</Image>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I'm pretty sure I'm missing the problem of your question, but the following code works for me:
<Window.Resources>
<Image x:Key="test" Source="/Images/ChangeCase.png"/>
</Window.Resources>
<!-- Using a Resource for the Content -->
<Button Width="100" Height="20" Content="{StaticResource test}"/>
<!-- Specifying the Content directly -->
<Button Width="100" Height="20">
<Image Source="/Images/ChangeCase.png"/>
</Button>
Plus I spotted an error in your code:
<Button Content="{{StaticResource closeImage}" [...]
should be:
<Button Content="{StaticResource closeImage}" [...]
I don't quite understand what your style is doing. Why do you have the Content Property set to a StaticResource when you want to specify the image via style?
Edit:
Alright, I tried your style and it also works for me.
<Style x:Key="WindowToolboxButton" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid x:Name="grid" Height="15" Width="15">
<Border x:Name="border" CornerRadius="2,2,2,2" BorderBrush="#FFBBCDD2" BorderThickness="1" Opacity="0" Margin="0">
<Border.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF82A3AC" Offset="1"/>
<GradientStop Color="#7FCDD9DC"/>
</LinearGradientBrush>
</Border.Background>
</Border>
<Image x:Name="image" Source="/Images/ChangeCase.png" Stretch="None" VerticalAlignment="Center" HorizontalAlignment="Center" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Button Width="100" Height="20" Content="Test" Style="{DynamicResource WindowToolboxButton}"/>
The image is shown. However, I can't see your border due to the opacity-prop being set to 0.
The content that is given directly on the button is overriden by the style.
Maybe there is sth wrong with your image? Did you set its build-property to Resource?
I think the correct way of doing this is
Create a new custom control ImageButton which derives from Button
Create a DP 'ImageSource' of type 'ImageSource' in ImageButton and in its style bind the Source of the Image to this DP.
Then you can use it like <ImageButton ImageSource={StaticResource ...}/>
If you try to add an image defined in a resource to a content control it will only work the first time. The second time you try to add the same image into another content control it will fail with "Specified visual is already a child of another visual..."
Actually, this is really easy. Use the Style you already have and add the following to 'image'
Source="{Binding Content, RelativeSource={RelativeSource TemplatedParent}}"
Then (as long as you have the image set as Content/Copy if newer) you can set the Content with the desired image's Uri.
<Button Content="/[projectname];component/.../close.png" Style="{StaticResource WindowToolboxButton}" ... />
note: replace '[projectname]' with your project's name and the '...' with path to the image
Replace
<Image x:Name="image" Source="close.png" Stretch="None" VerticalAlignment="Center" HorizontalAlignment="Center" >
With
<Image x:Name="image" Source="{Binding Content, RelativeSource={RelativeSource AncestorType=Button}" Stretch="None" VerticalAlignment="Center" HorizontalAlignment="Center" >
Where your ancestor type will be That button that is called in xaml, and there you can Set Content of that button to point to some image.
Example:
<cc:customButton Content={StaticResource someImage}.../>

image button template?

I want Image button with two state(normal , mouse over). that button must change image with Mouse Over event trigger automatically.
this image button must be a user control. Also i want to set image for each state form code in which form i use that user control.
Solution is using a template with "Value Converter" but i don't know how?
Why must this image button be a user control? If a regular button with a new control template is fine, this should work:
<Button>
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Image Name="HoverImage" Source="hover_image.png" Visibility="Hidden" />
<Image Name="DefaultImage" Source="default_image.png" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="DefaultImage" Property="Visibility" Value="Hidden" />
<Setter TargetName="HoverImage" Property="Visibility" Value="Visible" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Template>
</Button>
If you need a simple rollover effect, you don't need a template for it.. article below has a solution to it..
http://www.c-sharpcorner.com/Resources/Detail.aspx?ResourceId=706
In this article user uses SolidColorBrush, you can use ImageBrush to set image as background of button.
I found This on Code-project-Article(Cool example)
http://www.codeproject.com/KB/WPF/WPF_xaml_taskbar_window.aspx
First He create Wpf-Custom-control(you can create class inherit from Button like this)
public class ImageButton : Button
{
private string cornerRadius;
public string CornerRadius
{
get { return cornerRadius; }
set { cornerRadius = value; }
}
private string highlightBackground;
public string HighlightBackground
{
get { return highlightBackground; }
set { highlightBackground = value; }
}
private string pressedBackground;
public string PressedBackground
{
get { return pressedBackground; }
set { pressedBackground = value; }
}
}
As second step you must Create template in resource-dictionary(here is code)
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Phone.Controls">
<ControlTemplate x:Key="ButtonTemplate" TargetType="{x:Type local:ImageButton}">
<ControlTemplate.Resources>
<Storyboard x:Key="MouseOverButton">
<ThicknessAnimation Storyboard.TargetName="ButtonBackgroundBorder"
Storyboard.TargetProperty="(Control.Margin)"
Duration="0:0:0.05"
FillBehavior="Stop"
From="0,0,0,0" To="2,2,2,2"
AutoReverse="True" />
</Storyboard>
</ControlTemplate.Resources>
<Grid x:Name="ButtonOuterGrid">
<Border x:Name="ButtonBackgroundBorder"
CornerRadius="{Binding Path=CornerRadius, RelativeSource={RelativeSource TemplatedParent}}"
Background="{Binding Path=HighlightBackground, RelativeSource={RelativeSource TemplatedParent}}"
BorderBrush="Black"
BorderThickness="0.8"
Opacity="0">
<Border.BitmapEffect>
<OuterGlowBitmapEffect GlowColor="#FFFFFFFF" GlowSize="2.75" Noise="0.20"/>
</Border.BitmapEffect>
</Border>
<Border x:Name="ButtonEdgesBorder" CornerRadius="{Binding Path=CornerRadius, RelativeSource={RelativeSource TemplatedParent}}"
Opacity="1"
BorderBrush="Transparent"
BorderThickness="0" />
<Border x:Name="ButtonContentBorder"
CornerRadius="{Binding Path=CornerRadius, RelativeSource={RelativeSource TemplatedParent}}"
Opacity="1"
BorderThickness="1">
<ContentPresenter x:Name="ContentText"
Width="Auto" Height="Auto"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Trigger.Setters>
<Setter Property="Opacity" TargetName="ButtonBackgroundBorder" Value="1"/>
<Setter Property="TextElement.Foreground" TargetName="ContentText" Value="Black"/>
</Trigger.Setters>
</Trigger>
<EventTrigger RoutedEvent="Grid.MouseEnter"
SourceName="ButtonOuterGrid">
<BeginStoryboard Storyboard="{StaticResource MouseOverButton}"/>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<Style x:Key="ImageButton" TargetType="{x:Type Button}">
<Setter Property="Template" Value="{StaticResource ButtonTemplate}" />
</Style>
And this is last Step, in xaml file you must insert this custom-control
<ImageButton x:Name="btnConfigs"
Style="{StaticResource ImageButton}"
Width="25" Height="25"
VerticalAlignment="Top"
HorizontalAlignment="Right"
Margin="0,31.125,16.418,0">
<Image x:Name="ImgConfigs"
Stretch="Fill"/>
</ImageButton >
and in cs file do this
this.ImgConfigs.Source="any imag-source"
also we can change this image-source on btnconfig-click event
With special thanks from Murray-Foxcroft for create that article

Resources