Change image background button image and restore old [duplicate] - wpf

I'm actually surprised that I didn't find the answer to this simple question here. I want to create a simple button with Image content. When pressed the image should change to another one and after the button is released change back to the original image. What is the easiest way to do this?
EDIT: This is not a toggle button!

You can achieve this using a ControlTemplate to specify the visual structure of your button.
The below XAML shows how to add an image to your button (maintaining the standard chrome border though you can remove this if you don't want it), plus adding a trigger on the isPressed event to set your other image. You'll need to include the namespace xmlns:Microsoft_Windows_Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Luna" as well if you want to use the chrome button border.
<Button>
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Microsoft_Windows_Themes:ButtonChrome x:Name="Chrome" BorderBrush="{TemplateBinding BorderBrush}" Fill="{TemplateBinding Background}" RenderMouseOver="{TemplateBinding IsMouseOver}" RenderDefaulted="{TemplateBinding IsDefaulted}" SnapsToDevicePixels="true" ThemeColor="NormalColor">
<Image x:Name="buttonImage" Source="defaultImage"/>
</Microsoft_Windows_Themes:ButtonChrome>
<ControlTemplate.Triggers>
<Trigger Property="IsPressed" Value="true">
<Setter Property="Source" TargetName="buttonImage" Value="onPressedImage"/>
</Trigger>
</ControlTemplate.Triggers>
</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. :)

WPF UserControl border blinking when moving mouse outside during command processing

I have written a WPF UserControl (let's called it ContainerUserControl), inside it it uses other UserControl (let's call it OstUserControl) which I build from another project. Within the ContainerUserControl, I have a RibbonGroup hosting bunch of RibbonButtons. The OtsUserControl can respond to user mouse clicks on a toggle button inside and runs the same code if user clicks a corresponding RibbonButton.
However the odd thing is: If I click the RibbonButton (which is outside of the border of the OtsUserControl), there is flickering around the boundary of OtsUserControl;
If I click a toggle button inside OtsUserControl and don't move the mouse outside the OtsUserControl, there is NO flickering;
If I click a toggle button inside OtsUserControl and move the mouse outside the OtsUserControl, there is flickering.
How can I fix this flickering problem?
BTW, the code to invoke it via RibbonButton goes through MVVM Light's RelayCommand mechanism.
I also have a file being shared on the SkyDrive. When you ran the sample application, after the MainWindow has been loaded, click on one of the tree node with folder icon and click the expander button as you do in windows explorer. You will see no flickering. However if you select the same node and click the Toggle Expand button on the toolbar, you will see the usercontrol border flickering.
To view it, click the link below.
sample VS 2012 project showing the flickering problem
This is the Default ListView Template (extracted using Blend):
<ControlTemplate TargetType="{x:Type ListView}">
<Microsoft_Windows_Themes:ListBoxChrome x:Name="Bd"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
RenderMouseOver="{TemplateBinding IsMouseOver}"
RenderFocused="{TemplateBinding IsKeyboardFocusWithin}"
SnapsToDevicePixels="true">
<ScrollViewer Padding="{TemplateBinding Padding}" Style="{DynamicResource {x:Static GridView.GridViewScrollViewerStyleKey}}">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</ScrollViewer>
</Microsoft_Windows_Themes:ListBoxChrome>
<ControlTemplate.Triggers>
<Trigger Property="IsGrouping" Value="true">
<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
The border blinks whenever the IsMouseOver or IsKeyboardFocusWithin are toggled.
If you don't want that, simply change these lines:
RenderMouseOver="{TemplateBinding IsMouseOver}"
RenderFocused="{TemplateBinding IsKeyboardFocusWithin}"
To:
RenderMouseOver="False"
RenderFocused="False"
You will need to add a reference to PresentationFramework.Aero.dll and add this xmlns:
xmlns:Microsoft_Windows_Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"

Image Button only responds when clicking on the image and not the area around inside the button

I'm using the following button style which takes away the borders and makes a transparent background to make my image buttons:
<Style x:Key="EmptyButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Background" Value="#00000000"/>
<Setter Property="BorderBrush" Value="#00000000"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Padding" Value="1"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<ContentPresenter
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Margin="{TemplateBinding Padding}"
RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The Style is from the following answer:
WPF button with image of a circle
The problem now is that the clickable area is confined to the image regardless of how big the actual button is:
My button code:
<Button Name="n02" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Style="{DynamicResource EmptyButtonStyle}" Canvas.Left="308" Canvas.Top="157" Height="106" Width="120">
<Image Source="boto_face_off.PNG" Height="61" Width="59" />
</Button>
Question: how do I make the whole button area react to the click? I want to keep it transparent and without border as it is now.
You could wrap the presenter in a Border with a bound Background.
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}">
<!-- ContentPresenter here -->
</Border>
</ControlTemplate>
The style sets the Background to something transparent but it was never even used in the Template, this way the Border will make the whole area hit-test.
Just adding some info to the answer above after investigating the issue for hours.
If you are defining your own template as in the example above you are changing the visual tree of the element. In the above example applying the Style="{DynamicResource EmptyButtonStyle}" it becomes:
Button
|
ContentPresenter
But if you look at the visual tree of a standard button(you can do this in Visual Studio) it looks like this:
Button
|
ButtonChrome
|
ContentPresenter
So in the styled button there is nothing around the ContentPresenter to be clicked on, and if the Content is in the "middle" the surrounding area will be left totally empty. We have to add an element to take this place:
You can do it with a <Border>(I think this is best because Border is a lightweight element I suppose) or some other element, I tried <Grid> and <DockPanel> and both worked.
The only thing I don't understand is why you need to explicitly set the background to something transparent, just leaving it out will not produce a clickable area.
Edit: Last point answered in the comments here Image Button only responds when clicking on the image and not the area around inside the button
I have Button where content is Grid containing Image and TextBlock
I fixed clickable area by adding Transparent Background to grid
Background="#00000000"

How to make a 2 state Image button?

I'm actually surprised that I didn't find the answer to this simple question here. I want to create a simple button with Image content. When pressed the image should change to another one and after the button is released change back to the original image. What is the easiest way to do this?
EDIT: This is not a toggle button!
You can achieve this using a ControlTemplate to specify the visual structure of your button.
The below XAML shows how to add an image to your button (maintaining the standard chrome border though you can remove this if you don't want it), plus adding a trigger on the isPressed event to set your other image. You'll need to include the namespace xmlns:Microsoft_Windows_Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Luna" as well if you want to use the chrome button border.
<Button>
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Microsoft_Windows_Themes:ButtonChrome x:Name="Chrome" BorderBrush="{TemplateBinding BorderBrush}" Fill="{TemplateBinding Background}" RenderMouseOver="{TemplateBinding IsMouseOver}" RenderDefaulted="{TemplateBinding IsDefaulted}" SnapsToDevicePixels="true" ThemeColor="NormalColor">
<Image x:Name="buttonImage" Source="defaultImage"/>
</Microsoft_Windows_Themes:ButtonChrome>
<ControlTemplate.Triggers>
<Trigger Property="IsPressed" Value="true">
<Setter Property="Source" TargetName="buttonImage" Value="onPressedImage"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Template>
</Button>

DataTemplate / ContentTemplate - exchange controls

How can i solve the following (simplified) problem?
M-V-VM context. I want to show text at the UI.
In case the user has the rights to change the text, i want to use a textbox to manipulate the text.
In case the user has no rights, i want to use a label to only show the text.
My main problem: how to exchange textbox and label and bind Text resp. Content to the same property in viewmodel.
Thanks for your answers
Toni
There are a few ways of achieving this, with varying degrees of ease of reuse. You can have a DataTemplateSelector that could return the appropriate DataTemplate for a given property (depending on how this is written, you may be able to use it for each of your properties).
You could create a DataTemplate for each property, and change visibility based on a DataTrigger (this gets really annoying, as it is a lot of copy and paste).
I think the easiest way of doing this is with a specialized ControlTemplate for the TextBox. Basically, when it is disabled, instead of graying it out, you can just make it look like a TextBlock:
<ControlTemplate x:Key="PermissionedTextBox" TargetType="{x:Type TextBox}">
<Border x:Name="bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}">
<ScrollViewer x:Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="bd" Property="BorderBrush" Value="{x:Null}" />
<Setter TargetName="bd" Property="Background" Value="{x:Null}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
Then you can use it like so:
<TextBox Text="{Binding PermissionedText}" IsEnabled="{Binding CanEdit}" />

Resources