How to make a 2 state Image button? - 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. :)

Change image background button image and restore old [duplicate]

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>

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"

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}" />

Silverlight 4 - Mousewheel stops scrolling ScrollViewer when over contained RichTextBox

I have a Silverlight 4 out-of-browser application with a ScrollViewer that has several RichTextBoxes inside. The RichTextBoxes are only used for displaying text, and are never edited and never scroll.
However when the mouse is hovering over a RichTextBox the mousewheel event seems to not reach the ScrollViewer. Is there any way to overcome this limitation?
The reason a readonly RichTextBox doesn't scroll is because the default template for RichTextBox uses a ScrollViewer instead of a ContentControl. So to solve the problem, you need to create your own template for RichTextBox.
What I did was to create a copy of the RichTextBox template in Blend, and strip it down for the readonly case. This removes about 90% of the template. The following style/template remains:
<Style TargetType="c:RichTextBlock">
<Setter Property="IsReadOnly" Value="True" />
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid x:Name="RootElement">
<Border x:Name="Border" CornerRadius="0"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
Padding="{TemplateBinding Padding}"
>
<ContentControl x:Name="ContentElement" IsTabStop="False" />
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Use this style/template for your readonly RichTextBox'es, and you should be good to go.
Goood luck,
Jim McCurdy
Face to Face Software and YinYangMoney

Resources