User Control Background Hides Children Controls - c#

A user control's background is set, but that background hides the contained controls. How can this be resolved?
<UserControl x:Class="PL_Wpf.CustomControls.Conditioner"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:PL_Wpf.CustomControls"
mc:Ignorable="d" Height="166" Width="349">
<UserControl.Background>
<ImageBrush ImageSource="Conditioner.png" Stretch="None"/>
</UserControl.Background>
<Grid >
<ComboBox x:Name="combo1" HorizontalAlignment="Right" Width="57" Margin="0,68,53.206,70" />
<ToggleButton x:Name="ToggleSwitch" Height="50" Click="ToggleSwitch_Click" Margin="97.205,55,115.206,61" d:LayoutOverrides="Width" >
<ToggleButton.Style>
<Style TargetType="{x:Type ToggleButton}">
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Content">
<Setter.Value>
<Image Source="../Pics/switch_on.png" />
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="IsChecked" Value="False">
<Setter Property="Content">
<Setter.Value>
<Image Source="../Pics/switch_off.png" />
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton>
</Grid>
jsfiddle.net/wgfw1Ld7/

The Margin properties on the controls set themselves when dropped on the design surface. This feature may be needed if adjusting items on a Canvas but are mostly an annoyance when dealing with most Xaml control placement.
Remove the Margin properties to see the controls in their correct location on the grid.

Related

Clicking on WPF ToggleButton changes other ToggleButtons values

I have a simple ToggleButton with Style triggers to change the button's image based on the state of IsChecked. This is working fine for one button. However when I add more than one button to a grid, clicking one of the ToggleButtons changes the state of the others. Should I use some other trigger type instead of one based on the botton's style?
Here is the xaml block to lay out the three ToggleButtons:
<Grid Height="362" Width="259">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<ToggleButton Style="{StaticResource TogglebuttonStyle}" IsChecked="{x:Null}" IsThreeState="True"
Width="15" Height="15" Grid.Row="0" Grid.Column="0"/>
<ToggleButton Style="{StaticResource TogglebuttonStyle}" IsChecked="{x:Null}" IsThreeState="True"
Width="15" Height="15" Grid.Row="1" Grid.Column="0"/>
<ToggleButton Style="{StaticResource TogglebuttonStyle}" IsChecked="{x:Null}" IsThreeState="True"
Width="15" Height="15" Grid.Row="2" Grid.Column="0"/>
</Grid>
And here is the Style with triggers:
<Style x:Key="TogglebuttonStyle" TargetType="ToggleButton">
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Content">
<Setter.Value>
<Image Source="{StaticResource ImagePlus}"/>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="IsChecked" Value="False">
<Setter Property="Content">
<Setter.Value>
<Image Source="{StaticResource ImageMinus}"/>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="IsChecked" Value="{x:Null}">
<Setter Property="Content">
<Setter.Value>
<Image Source="{StaticResource ImageNeutral}"/>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
I'll call this a workaround, but now each button retains its own state:
I found if I moved my Style block out of App.xaml (within the tag) and defined style triggers for each button, the problem behavior went away. Since I'm fairly new to WPF/XAML I'm not sure if it's an actual solution or a hacky workaround. It seems redundant to specify things this way.
<ToggleButton IsChecked="True" IsThreeState="True"
Width="25" Height="25" Grid.Row="2" Margin="-1,19,1,-19">
<ToggleButton.Style>
<Style TargetType="ToggleButton">
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Content">
<Setter.Value>
<Image Source="{StaticResource ImagePlus}"/>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="IsChecked" Value="False">
<Setter Property="Content">
<Setter.Value>
<Image Source="{StaticResource ImageMinus}"/>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="IsChecked" Value="{x:Null}">
<Setter Property="Content">
<Setter.Value>
<Image Source="{StaticResource ImageNeutral}"/>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton>
After doing some more research, I found I had to specify that the style not be shared.
<Style x:Key="ToggleButtonStyle" x:Shared="False" /Style>
The problem is that the setter instantiates one instance of the Image control, which can have only one parent. When then button goes into the "ImagePlus" state, all's well. When a second button goes into that state, that Image control gets moved to the new parent, leaving the old one bereft.
This is one reason why XAML has templates: When a template is instantiated, a new instance of that snippet of visual tree gets instantiated. Presto, no sharing issues.
With some resources you can set x:Shared="False" on the resource and get around this issue. I couldn't find a way to make that work here (I've not yet gotten around to figuring out the principle behind exactly when that works and when not). So I did it with DataTemplates instead:
<Style x:Key="TogglebuttonStyle" TargetType="ToggleButton" BasedOn="{StaticResource {x:Type ToggleButton}}">
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Image Source="{StaticResource ImagePlus}" />
</DataTemplate>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="IsChecked" Value="False">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Image Source="{StaticResource ImageMinus}" />
</DataTemplate>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="IsChecked" Value="{x:Null}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Image Source="{StaticResource ImageNeutral}" />
</DataTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>

Change UserControl content in WPF

I have following UserControl defined in wpf:
<UserControl x:Class="Views.HideShowDetailsView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d">
<DockPanel Background="#FFFFF2CC" Name="HideShowDetailsPanel">
<Button Name="hidePatientDetails"
Background="Transparent"
Margin="10,10"
Width="40"
BorderBrush="Transparent"
BorderThickness="0"
DockPanel.Dock="Right"
Command="{Binding Path=HideDetailsCommand}" >
<Button.Template>
<ControlTemplate TargetType="Button">
<Image Source="../Resources/ArrowRight.png" />
</ControlTemplate>
</Button.Template>
</Button>
</DockPanel>
</UserControl>
And I need to change it's content by adding image canvas and another button when Command is activated. How this can be achieved in wpf?
You can do it by adding the two new controls to a container, say, StackPanel somewhere inside your UC. Then assign the following style to the StackPanel:
<Style x:Key="stackStyle" TargetType="StackPanel">
<Setter Property="Visibility" Value="Visible" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsEnabled, ElementName=hidePatientDetails}" Value="False">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>

How to change WPF Rectangle Style Programatically

[EDIT] *I had forgotten to include the Exception returned
'System.Windows.Style' is not a valid value for property 'Fill'*
This is my first post, I've already done lots of searching for questions where this might have already been answered to no success. I'm a complete noob when it comes to MVVM, Prism, and WPF and I have been thrown in the deep end on this one.
I wish to change the contents of 2 rectangles depending on a boolean in the Model (Binding Passed).
if a test returns Pass (bool True) then we display colour Green for first rectangle, and the second rectangle will display the UserControl.Resource Style x:Key="RectanglePass".
If test fails, then first rectangle is red, and second displays UserControl.Resource Style x:Key="RectangleFail"
I have the following xaml code:
<UserControl x:Class="Integration.Memjet.Aoqc.Views.ProcessResultView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<Style x:Key="RectangleFail" TargetType="Rectangle">
<Setter Property="Fill">
<Setter.Value>
<VisualBrush>
....
</VisualBrush>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="RectanglePass" TargetType="Rectangle">
<Setter Property="Fill">
<Setter.Value>
<VisualBrush>
....
</VisualBrush>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="60"></RowDefinition>
<RowDefinition Height="60"></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Label VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="20">PASS</Label>
<Rectangle Name="rectStatus" Grid.Row="1">
<Rectangle.Style>
<Style TargetType="{x:Type Rectangle}">
<Style.Triggers>
<DataTrigger Binding="{Binding Passed}" Value="True">
<Setter Property="Fill" Value="Green" />
</DataTrigger>
<DataTrigger Binding="{Binding Passed}" Value="False">
<Setter Property="Fill" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</Rectangle.Style>
</Rectangle>
<Rectangle Name="rectStatusImg" Width="120" Height="120" Grid.Row="2" >
<Rectangle.Style>
<Style TargetType="{x:Type Rectangle}">
<Style.Triggers>
<DataTrigger Binding="{Binding Passed}" Value="True">
<Setter Property="Fill" Value="{StaticResource RectanglePass}" />
</DataTrigger>
<DataTrigger Binding="{Binding Passed}" Value="False">
<Setter Property="Fill" Value="{StaticResource RectangleFail}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Rectangle.Style>
</Rectangle>
</Grid>
</UserControl>
The above doesn't work and returns an exception.
If I was to replace the second Rectangle tag (rectStatusImg) with this line;
<Rectangle Name="rectStatusImg" Style="{StaticResource RectanglePass}" Width="120" Height="120" Grid.Row="2" ></Rectangle>
the xaml works and produces the expected result! But I wish to bind it to the Boolean Passed so I can change it programmatically.
I really hope I was able to explain my problem here.
Thank you for your help in advance, this site has always been a treasure and a great help.
Cheers,
Simon
define two visual brushes in your resource and create a style of rectangle with data trigger like
<VisualBrush x:Key="FailBrush">Black</VisualBrush>
<VisualBrush x:Key="PassBrush">Red</VisualBrush>
<Style x:Key="ColorRectangleStyle" TargetType="Rectangle">
<Setter Property="Fill" Value="{StaticResource FailBrush}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Passed}" Value="False">
<Setter Property="Fill" Value="{StaticResource PassBrush}"/>
</DataTrigger>
</Style.Triggers>
</Style>
and use it in rectangle like
<Rectangle Name="rectStatusImg" Width="120" Height="120" Grid.Row="2" Style="{StaticResource ColorRectangleStyle}" />
Hope it helps.

WPF TabControl tabs "jumping"

I'm creating a WPF tab control which contains tabs rotated 270° When I mouse the mouse over between tabs they appear to be "jumping". I'm looking for a way to prevent this from happening.The tabs should have the same behaviour as the tabs in Microsoft Office ribbon UI(stay in a fixed position). Is it possible to modify the XAML below to achieve this?
XAML:
<Window x:Class="WpfApplication2.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="350" Width="300" TextOptions.TextFormattingMode="Display" TextOptions.TextRenderingMode="ClearType" UseLayoutRounding="true">
<TabControl TabStripPlacement="Left" BorderThickness="1,0,0,0">
<TabControl.ItemContainerStyle>
<Style TargetType="{x:Type TabItem}">
<Setter Property="LayoutTransform">
<Setter.Value>
<RotateTransform Angle="270"/>
</Setter.Value>
</Setter>
<Setter Property="Foreground" Value="#330033" />
<Setter Property="FontSize" Value="9pt"/>
<Setter Property="Height" Value="22" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid>
<Border Background="White" Name="Border" BorderBrush="#A9A9A9" BorderThickness="0" CornerRadius="2,2,0,0">
<Border Padding="2" BorderBrush="Transparent">
<ContentPresenter x:Name="ContentSite"
VerticalAlignment="Center"
HorizontalAlignment="Center"
ContentSource="Header"
Margin="12,0,12,2"/>
</Border>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Panel.ZIndex" Value="100" />
<Setter TargetName="Border" Property="BorderThickness" Value="1,1,1,0" />
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Panel.ZIndex" Value="100" />
<Setter TargetName="Border" Property="BorderThickness" Value="1,1,1,0" />
<Setter TargetName="Border" Property="Background" Value="White" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</TabControl.ItemContainerStyle>
<TabItem Header="Tab item 1" />
<TabItem Header="Tab item 2" />
<TabItem Header="Tab item 3" />
</TabControl>
</Window>
I think it would be better to hide a Border when the mouse is not over a tab by setting the Border's BorderBrush to Transparent rather than setting its BorderThickness to zero.
In other words, change
<Border Background="White" Name="Border" BorderBrush="#A9A9A9" BorderThickness="0" CornerRadius="2,2,0,0">
to
<Border Background="White" Name="Border" BorderBrush="Transparent" BorderThickness="1,1,1,0" CornerRadius="2,2,0,0">
and in the IsMouseOver trigger, use
<Setter TargetName="Border" Property="BorderBrush" Value="#A9A9A9" />
in place of a setter on the BorderThickness.
In your case, the border element itself changes size when you change its BorderThickness because the BorderThickness contributes to the 'size' of the Border, and the control inside it doesn't change size.
If you remove the below line (border) from the IsMouseOver trigger it stops jumping and visually it doesn't really have a huge effect (in my opinion).
<Setter TargetName="Border" Property="BorderThickness" Value="0,0,0,0" />

WPF change visual state of datatemplate when selected in a listbox

If I have a WPF ListBox which has a basic ItemTemplate that contains a custom user control, how can I tell the user control in the DataTemplate to change its visual state when its selected in the ListBox?
Thanks a lot for any help you can give
You can style the ListBoxItem to trigger on the IsSelected property. Here's an example:
ListBoxItem ControlTemplate Example
and then you use it like this:
<ListBox ItemContainerStyle="{StaticResource yourListBoxItemStyle}">
or directly in the ListBox itself:
<ListBox.ItemContainerStyle>
<Style TargetType=”ListBoxItem”>
...
</Style>
</ListBox.ItemContainerStyle>
Edit:
Here is a complete example with both an ItemTemplate and an ItemContainerStyle that puts a semi-opaque layer on top of the selected item.
<Grid>
<Grid.Resources>
<x:Array Type="sys:String" x:Key="sampleData">
<sys:String>Red</sys:String>
<sys:String>Green</sys:String>
<sys:String>Blue</sys:String>
</x:Array>
<DataTemplate x:Key="listBoxItem">
<Rectangle Fill="{Binding}" Width="100" Height="100"/>
</DataTemplate>
<Style TargetType="ListBoxItem" x:Key="listBoxItemStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Grid>
<ContentPresenter />
<Rectangle x:Name="Rectangle" Fill="Black" Opacity="0"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="Rectangle" Property="Opacity"
Value="0.5"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<ListBox
ItemsSource="{StaticResource sampleData}"
ItemTemplate="{StaticResource listBoxItem}"
ItemContainerStyle="{StaticResource listBoxItemStyle}"
/>
</Grid>
Edit
After a comment, here is the version using a "unified" template:
<Style TargetType="ListBoxItem" x:Key="listBoxItemStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Grid>
<Rectangle Name="Rectangle" Fill="{Binding}" Width="100" Height="100" Opacity="1"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="Rectangle" Property="Opacity"
Value="0.5"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

Categories

Resources