WPF Image Command Binding - wpf

I'm putting a WPF application together in which I have an image control which I want to bind a custom command object to from my view model that will execute when the image is clicked. I have exposed the command object from my view model and just need to bind it to the image control.
Is it possible to bind this command object to an image control? If so any advice would be appreciated.

Here's yet another solution I personally love to use most of the time if I want an image with command without enclosing it in another control.
<Image Source="Images/tick.png" Cursor="Hand" Tooltip="Applies filter">
<Image.InputBindings>
<MouseBinding Gesture="LeftClick" Command="{Binding ApplyFilter, Mode=OneTime}" />
</Image.InputBindings>
</Image>
I set its properties Hand and Tooltip so that it's more clear that it's an action and not a static image.

You need to put the image in a button, and bind the button to the command:
<Button Command="{Binding MyCommand}">
<Image Source="myImage.png" />
</Button>
If you don't want the standard button chrome, just change the template of the button with something like that:
<ControlTemplate x:Key="tplFlatButton" TargetType="{x:Type Button}">
<Border Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
TextElement.Foreground="{TemplateBinding Foreground}"
TextElement.FontFamily="{TemplateBinding FontFamily}"
TextElement.FontSize="{TemplateBinding FontSize}"
TextElement.FontStretch="{TemplateBinding FontStretch}"
TextElement.FontWeight="{TemplateBinding FontWeight}"/>
</Border>
</ControlTemplate>
Note that you will also need to change other properties to override the default button style, otherwise the template above will use the default button background and border:
<Style x:Key="stlFlatButton" TargetType="{x:Type Button}">
<Setter Property="Background" Value="{x:Null}" />
<Setter Property="BorderBrush" Value="{x:Null}" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Template" Value="{StaticResource tplFlatButton}" />
</Style>

It can be simpler to avoid using a button and use a Hyperlink instead:
<TextBlock DockPanel.Dock="Top">
<Hyperlink Command="{Binding SomeCommand}">
<Image Source="image.png" />
</Hyperlink>
</TextBlock>
Note that this will render the hyperlink with the default text decoration, so you'll want to add a style that removes that - putting this in the resource dictionary of the containing element will do the trick:
<Style x:Key={x:Type Hyperlink}" TargetType="Hyperlink">
<Setter Property="TextDecorations"
Value="{x:Null}" />
</Style>

Simplified version of answer from #Robert Rossney:
<TextBlock>
<Hyperlink Command="{Binding SomeCommand}" TextDecorations="{x:Null}">
<Image Source="{StaticResource image.png}" Width="16" />
</Hyperlink>
</TextBlock>
The best way to include an image is to use a {StaticResource x}, see WPF image resources

reset control template of the button and use image in control template..
<Button Width="100" Height="100" Command="{Binding SampleCommand}">
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Image Stretch="Uniform" Source="Images/tick.png"></Image>
</ControlTemplate>
</Button.Template>
</Button>

Related

WPF variable custom button shape

I'm trying to desinge a Template for a Button, which addapts the shape of the Button. I want to give the shape as Attribute to the control. Like this:
<Button Style="{StaticResource MyStyle}">
<Button.Shape>
<ImageBrush ImageSource="MyImage"/>
</Button.Shape>
</Button>
I tried to use the OpacityMask-Attribute of the Button, but somehow I coulden't specify in the template on which element I want to apply the mask.
<ControlTemplate x:Key="Test" TargetType="Button">
<Grid Background="{TemplateBinding Background}"
SnapsToDevicePixels="True">
<Rectangle Fill="{TemplateBinding Foreground}" OpacityMask"{TemplateBinding OpacityMask}">
</Rectangle>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="#aaff00ff"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
I already tried something like this:
<Button Style="{StaticResource MyStyle}">
<Button.OpacityMask>
<ImageBrush ImageSource="MyImage"/>
</Button.OpacityMask>
</Button>
But then i can't change the background anymore. I know, I could put every button in a Grid with the background I want, but I try to learn the concept of Templates and I wonder if there is a more elegant solution. :)

Make ErrorTemplate in Style on ComboBox allow tooltip but not mouse click

I use telerik, but that should not mean much for this question. My application is WPF (.Net 4.5).
I have a style, that I use for all comboboxes, which has an errortemplate. The style looks like this:
<Style TargetType="{x:Type telerik:RadComboBox}" x:Key="RadComboBoxStyle" >
<Setter Property="FontFamily" Value="Calibri"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="Background" Value="{StaticResource InputBrush}" />
<Setter Property="BorderBrush" Value="{StaticResource InputBorderBrush}" />
<Setter Property="Validation.ErrorTemplate" Value="{StaticResource RadComboBoxValidationErrorTemplate}" />
</Style>
My ErrorTemplate looks like this:
<ControlTemplate TargetType="{x:Type Control}" x:Key="RadComboBoxValidationErrorTemplate">
<Grid ToolTipService.IsEnabled="True" ToolTipService.ShowOnDisabled="True"
ToolTip="{Binding ElementName=customAdorner, Path=AdornedElement.(Validation.Errors), Converter={StaticResource ValidationErrorsConverter}}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Border BorderBrush="{StaticResource ErrorBrush}" BorderThickness="3" Panel.ZIndex="999" HorizontalAlignment="Right" Margin="0,0,10,0"
Background="Transparent" DockPanel.Dock="right" Width="16" Height="16" CornerRadius="10">
<Rectangle Fill="{StaticResource ErrorBrush}" HorizontalAlignment="Stretch" VerticalAlignment="Center" Height="3" RenderTransformOrigin="0.5,0.5">
<Rectangle.RenderTransform>
<RotateTransform Angle="315" />
</Rectangle.RenderTransform>
</Rectangle>
</Border>
<AdornedElementPlaceholder Name="customAdorner" VerticalAlignment="Center" >
<Border BorderBrush="{StaticResource ErrorBrush}" BorderThickness="1" />
</AdornedElementPlaceholder>
</Grid>
</ControlTemplate>
The entire thing is defined in a global ResourceDictionary.
What this code does, it to put a "forbidden sign" on top of the combobox (Panel.ZIndex="999"), just before the dropdown button (using margins). The Border and the Rectangle makes a sign much like this: Picture.
The combobox itself must be able to hold a tooltip, set locally. So the error-message cannot be shown in the tooltip of the combobox - unless I find a way to combine the two without having to resolve it locally (I want that code in my resourcedictionary).
I also do not want the "forbidden sign" to handle mouse clicks (it gobbles up the click and prevent the combobox from dropping down, if the user clicks on the "forbidden sign".
I tried setting IsHitTestVisible to false on the grid and on the border inside the ErrorTemplate, but that caused the Tooltip to never show.
I also tried setting IsEnabled to false on the same two constrols, but that would not send the mouseclick on to the combobox itself (the list in the combobox does not drop down).
Is there any way to do this directly in the combobox-style or errortemplate? I do not even mind having a code behind - but I really do not want to add code locally where the combobox-style is used.

Canvas with Children as a Style

Sorry if this is a dense question, but I'm looking to see if there is a way to have a style resource of Canvas in App.xaml and also have children on that Canvas and just refer to it in the Style of another canvas. The resource I envision would be something like:
<Style x:Key="Background1" TargetType="Canvas">
<Setter Property="Width" Value="500"/>
<Setter Property="Height" Value="600" />
<Setter Property="Background" Value="Red"/>
<Setter Property="Children">
<Setter.Value>
<Rectangle Canvas.Top="20" Canvas.Left="20" Width="100" Height="100" Fill="Yellow"></Rectangle>
</Setter.Value>
</Setter>
</Style>
And then calling it would be as simple as:
<Canvas Style="{StaticResource Background1}" x:Name="CanvasRoot" >
<Rectangle x:Name="PageRectangle" Canvas.Left="114" Canvas.Top="84" Height="378" Width="210" Stroke="#92D050" Fill="#C0504D" />
</Canvas>
Any thoughts on if something like this can be done. What I've done doesn't work because there is no "Children" property on Canvas.
So you want to add a child to a Canvas via a Style? I'm afraid this is simply not possible. Styles allows you to set the values of an elements dependency properties, such as Height, Background, Stroke etc ... You can also use them to set attached properties. However, the Children property you are trying to set is not a dependency property, it is the collection of children elements that describe the children of your canvas in the visual tree.
The only way to add new elements t the visual tree using styles is to add them to some controls template. Unfortunately you canot template panels (Canvas, Grid, StackPanel). You could use a ContentControl and add your rectangle as part of its template.
A ContentControl is a lookless container of a single child. See the template described here:
http://msdn.microsoft.com/en-us/library/dd334411%28VS.95%29.aspx
Here it is, templates to add a rectangle. I am not sure what layout you are trying to achieve, but it should give you the general idea
<Style TargetType="ContentControl" x:Key="myContentControl">
<Setter Property="Foreground" Value="#FF000000"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="VerticalContentAlignment" Value="Top"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContentControl">
<Canvas>
<Rectangle Canvas.Top="20" Canvas.Left="20" Width="100" Height="100" Fill="Yellow"></Rectangle>
<ContentPresenter
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Cursor="{TemplateBinding Cursor}"
Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Canvas>
</ControlTemplate>
</Setter.Value>
</Setter>
<ContentControl Style={StaticResource myContentControl}>
<Canvas x:Name="CanvasRoot" >
<Rectangle x:Name="PageRectangle" Canvas.Left="114" Canvas.Top="84" Height="378" Width="210" Stroke="#92D050" Fill="#C0504D" />
</Canvas>
</ContentControl>

Silverlight: Binding a custom control to an arbitrary object

I am planning on writing a hierarchical organizational control, similar to an org chart. Several org chart implementations are out there, but not quite fit what I have in mind.
Binding fields in a DataTemplate to a custom object does not seem to work.
I started with a generic, custom control, i.e.
public class NodeBodyBlock : ContentControl
{
public NodeBodyBlock()
{
this.DefaultStyleKey = typeof(NodeBodyBlock);
}
}
It has a simple style in generic.xaml:
<Style TargetType="org:NodeBodyBlock">
<Setter Property="Width" Value="200" />
<Setter Property="Height" Value="100" />
<Setter Property="Background" Value="Lavender" />
<Setter Property="FontSize" Value="11" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="org:NodeBodyBlock">
<Border Width="{TemplateBinding Width}" Height="{TemplateBinding Height}"
Background="{TemplateBinding Background}" CornerRadius="4" BorderBrush="Black" BorderThickness="1" >
<Grid>
<VisualStateManager/> ... clipped for brevity
</VisualStateManager.VisualStateGroups>
<ContentPresenter Content="{TemplateBinding Content}"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
My plan now is to be able to use this common definition as a base definition of sorts, with customized version of it used to display different types of content.
A simple example would be to use this on a user control with the following style:
<Style TargetType="org:NodeBodyBlock" x:Key="TOCNode2">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=NodeTitle}"/>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
and an instance defined as
<org:NodeBodyBlock Style="{StaticResource TOCNode2}" x:Name="stTest"
DataContext="{StaticResource DummyData}" />
The DummyData is defined as
<toc:Node NodeNumber="mynum" NodeStatus="A"
NodeTitle="INLine Node Title!"
x:Key="DummyData"/>
With a simple C# class behind it, where each of the fields is a public property.
When running the app, the Dummy Data values simply do not show up in the GUI. A trivial test such as
<TextBlock Text="{Binding NodeTitle}" DataContext="{StaticResource DummyData}"/>
works just fine.
Any ideas around where I am missing the plot?
Update: Binding to the datacontext in the definition in generic.xaml works fine, but any binding in the ContentPresenter is lost.
Your control template is missing a binding on the ContentPresenter, it should look like this:-
<ContentPresenter Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
I just ended up using this example as a base:
http://10rem.net/blog/2010/02/05/creating-customized-usercontrols-deriving-from-contentcontrol-in-wpf-4
Not quite sure what I missed, but the example works.

How to make a simple hyperlink in XAML?

All I want to do is make a little hyperlink in XAML. I've tried everything. I give up.
What is the syntax for this?
<StackPanel Width="70" HorizontalAlignment="Center">
<Hyperlink Click="buttonClose_Click" Cursor="Hand"
Foreground="#555" Width="31" Margin="0 0 0 15"
HorizontalAlignment="Right">Close</Hyperlink>
<Button Width="60" Margin="0 0 0 3">Test 1</Button>
<Button Width="60" Margin="0 0 0 3">Test 2</Button>
<Button Width="60" Margin="0 0 0 3">Test 3</Button>
<Button Width="60" Margin="0 0 0 3">Test 4</Button>
</StackPanel>
Visual Studio Team: In Visual Studio 2010 I want Clippy to pop up and say "It seems you are trying to make a hyperlink" and tell me how to do it. Can't you do that with MEF? It would be retro cool, and these little "how do I do what I already know how to do in HTML" issues burn up so much time during the learning process with XAML.
You can't add a Hyperlink to a StackPanel -- you'll get a runtime error. (Actually, I'm kinda surprised it's not a compile-time error.) That's because Hyperlink doesn't live in the "controls" side of WPF with <Button> and <StackPanel> and other things that are laid out on rectangular chunks of screen and descend from UIElement. Instead, it lives in the "text" side of things, with <Bold> and <Run> and <Paragraph> and other generally texty things that word-wrap and flow in lines and paragraphs and descend from TextElement.
Once you realize that there are two separate class hierarchies with different layout behaviors, it makes sense that Hyperlink would be on the "text" side of things (makes it easy to e.g. have a paragraph with a hyperlink in the middle, and even for that hyperlink to wrap across a line break).
But no, it's not so discoverable when you're starting out.
To mix the two worlds, and use a hyperlink as a control, all you need to do is put it in a TextBlock. TextBlock is a control-ish thing (i.e., can go in a StackPanel) that contains text-ish things (i.e., can contain a Hyperlink):
<TextBlock><Hyperlink Click="buttonClose_Click">Close</Hyperlink></TextBlock>
You can use a Button with a custom control template, the code below is a limited hyperlink style button (for example it only support textual hyperlinks) but maybe it'll point you in the right direction.
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<Style x:Key="Link" TargetType="Button">
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Foreground" Value="Blue"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<TextBlock TextDecorations="Underline"
Text="{TemplateBinding Content}"
Background="{TemplateBinding Background}"/>
<ControlTemplate.Triggers>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Foreground" Value="Red"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Page.Resources>
<Button Content="Click Me!" Style="{StaticResource Link}"/>
</Page>
Try this:
<TextBlock>
<Hyperlink RequestNavigate="Hyperlink_RequestNavigate"
NavigateUri="http://www.msn.com">MSN</Hyperlink>
</TextBlock>
private void Hyperlink_RequestNavigate(object sender,
System.Windows.Navigation.RequestNavigateEventArgs e)
{
System.Diagnostics.Process.Start(e.Uri.AbsoluteUri);
}
<TextBlock>
<Hyperlink NavigateUri="{Binding YourUri}" RequestNavigate="YourRequestNavigate">
<TextBlock Text="{Binding YourText}" />
</Hyperlink>
</TextBlock>
This will linkify any binded text in the nested textblock, i have not found a better way yet, i would like the first textblock to not be there if possible.
This will work for DataTemplates aswell.
You may find that if you're binding to anything other than simple text values you will need to use ContentPresenter otherwise nothing will appear, this could be true if you're binding to an XML data source.
A Property Trigger for IsMouseOver gives the text an underline.
An example where I"m binding to XML is presented below.
<Style x:Key="JobNumberStyleButton" TargetType="{x:Type Button}">
<Setter Property="VerticalAlignment" Value="Top"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<TextBlock>
<ContentPresenter
Margin="0,0,0,0"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
ContentStringFormat="{TemplateBinding ContentStringFormat}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
RecognizesAccessKey="False"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</TextBlock>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<TextBlock Padding="0,0,0,0" Margin="0,0,0,0">
<Underline>
<ContentPresenter
Margin="0,0,0,0"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
ContentStringFormat="{TemplateBinding ContentStringFormat}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
RecognizesAccessKey="False"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Underline>
</TextBlock>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
You can simply use HyperlinkButton.
When it is clicked on, the URL will be displayed in your web browser:
<HyperlinkButton
NavigateUri="https://dev.windowsphone.com"
TargetName="_blank"
Content="Windows Phone Dev Center" />
Usually, the meaning of an Hyperlink is to give an anchor to send the user to another Page or generally speaking to another resource, so it's implemented in such a way and you have to specify the location for that resource like this:
<HyperLink NavigateUri="http://www.site.com">
Web Site
</HyperLink>
However, i've found this blog post with a custom TextBlock that is used as an HyperLink and supports click events.
in UWP with mvvmcross i'm using this
<HyperlinkButton Content="{Binding TextSource, ConverterParameter=MyUrl, Converter={StaticResource Language},
FallbackValue=_MyUrl}" NavigateUri="http://www.google.com" />

Resources