WPF Button IsEnabled Based on ComboBox Selection Overwriting default style - wpf

I have a Button that is looking at 2 comboboxes to make sure they have a value before it is enabled. The problem is the way I am doing it is overwriting the default style declared in my theme project.
<Button x:Name="btnOK" VerticalAlignment="Center" Content="OK" IsDefault="True" Margin="0" Click="btnOK_Click">
<Button.Style>
<Style BasedOn="{StaticResource DefaultButton}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=ddlWageTypes, Path=SelectedItem}" Value="{x:Null}">
<Setter Property="Button.IsEnabled" Value="false"/>
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=ddlJobTitles, Path=SelectedItem}" Value="{x:Null}">
<Setter Property="Button.IsEnabled" Value="false"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
I've tried adding BasedOn="{StaticResouce MyDefaultButtonStyleName}" to the style tag but it blows up at runtime.
The error is "'System.Windows.Style' value cannot be assigned to property 'Style' of object 'System.Windows.Controls.Button'. Can only base on a Style with target type that is base type 'IFrameworkInputElement'. Error at object 'System.Windows.Style' in markup file"
Is there a was to do this in XAML without overwriting default style.
EDIT: Code Sample Updated.
I get an error on OKButtonStyle saying "Cannot add element to property 'Resources', because the property can have only one child element if it uses an explicit collection tag. Error at object 'System.Windows.Style' in markup file "
<UserControl x:Class="UK.Budgeting.XBAP.ShiftDiff.NewFTEPremiumPaySummary"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:compModel="clr-namespace:System.ComponentModel;assembly=WindowsBase"
xmlns:local="clr-namespace:UK.Budgeting.XBAP.ShiftDiff">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="CellTemplates.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
<Style TargetType="{x:Type Button}" x:Key="OKButtonStyle" BasedOn="{StaticResource DefaultButton}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=ddlWageTypes, Path=SelectedItem}" Value="{x:Null}">
<Setter Property="Button.IsEnabled" Value="false"/>
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=ddlJobTitles, Path=SelectedItem}" Value="{x:Null}">
<Setter Property="Button.IsEnabled" Value="false"/>
</DataTrigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
<Grid>
<Rectangle Style="{StaticResource DialogRectangle}"/>
<Border Style="{StaticResource DialogBorder}">
<Grid HorizontalAlignment="Center" VerticalAlignment="Center" Background="White">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="5"/>
<ColumnDefinition MinWidth="300"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="2"/>
<RowDefinition/>
<RowDefinition Height="2"/>
<RowDefinition/>
<RowDefinition Height="2"/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Grid.Column="0" Grid.Row="0" Style="{StaticResource LabelStyle}">Wage Type</TextBlock>
<TextBlock Grid.Column="0" Grid.Row="2" Style="{StaticResource LabelStyle}">Job Title</TextBlock>
<ComboBox x:Name="ddlWageTypes" VerticalAlignment="Top" Grid.Column="2" Grid.Row="0"
DisplayMemberPath="DisplayName"
SelectedValuePath="WageTypeCode"/>
<ComboBox x:Name="ddlJobTitles" VerticalAlignment="Top" Grid.Column="2" Grid.Row="2"
DisplayMemberPath="JobTitle"
SelectedValuePath="JobCode"/>
<StackPanel Grid.Column="2" Grid.Row="6" VerticalAlignment="Top" Orientation="Horizontal" Margin="5">
<Button x:Name="btnOK" VerticalAlignment="Center" Content="OK" IsDefault="True" Margin="0" Click="btnOK_Click" Style="{StaticResource OKButtonStyle}"/>
<Button x:Name="btnCancel" VerticalAlignment="Center" Content="Cancel" IsCancel="True" Margin="10,0,0,0" Click="btnCancel_Click"/>
</StackPanel>
</Grid>
</Border>
</Grid>
</UserControl>

How is this
BasedOn="{StaticResouce DefaultButton}"
supposed to refer to the default button style? This crashes because DefaultButton is an undefined resource in your app.
It should be:
BasedOn="{StaticResource {x:Type Button}}"
EDIT: Sorry, answered too hastily.
I noticed now your button has a Style={} set, and is pointing to a style called OkBUttonStyle. This is the style that should define everything and be based on the default button style. By everything, I include those triggers. What you are saying in the XAML is that Style is the Content of your Button.
Maybe some code will help:
<Window x:Class="WindowsApplication7.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WindowsApplication7" Height="300" Width="300"
>
<Window.Resources>
<Style TargetType="{x:Type Button}" x:Key="defaultButtonStyle">
<Setter Property="Background" Value="Red" />
</Style>
<Style TargetType="{x:Type Button}" x:Key="okButtonStyle" BasedOn="{StaticResource defaultButtonStyle}">
<Setter Property="Foreground" Value="Green" />
<Style.Triggers>
<Trigger Property="IsEnabled" Value="True">
<Setter Property="Background" Value="Yellow" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="Blue" />
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel>
<Button>System default</Button>
<Button Style="{StaticResource defaultButtonStyle}">My Default</Button>
<Button Style="{StaticResource okButtonStyle}">Ok</Button>
<Button Style="{StaticResource okButtonStyle}" IsEnabled="False">Ok disabled</Button>
</StackPanel>
</Window>

Related

Stackpanel IsMouseOver Trigger does not change to true

I have a Stackpanel with a Image in it. The Image is partly transperent.
So i want the Background to be Red, when the mouse is not over (which works). But wen the mouse is over it should turn into green. But it doesn't work. Can you please help me out.
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:shell="clr-namespace:System.Windows.Shell;assembly=PresentationFramework">
<Style x:Key="PhoenixWindowStyle" TargetType="{x:Type Window}">
<Setter Property="shell:WindowChrome.WindowChrome">
<Setter.Value>
<shell:WindowChrome GlassFrameThickness="0"
ResizeBorderThickness="1"
CaptionHeight="32"
CornerRadius="0"/>
</Setter.Value>
</Setter>
<Setter Property="Background" Value="{DynamicResource DefaultBackgroundBrush}"/>
<Setter Property="MinWidth" Value="100"/>
<Setter Property="MinHeight" Value="100"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Window}">
<Grid Background="{DynamicResource BorderBrush}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="1"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="32"/>
<RowDefinition Height="*"/>
<RowDefinition Height="1"/>
</Grid.RowDefinitions>
<DockPanel Grid.Column="1" Grid.Row="0">
<TextBlock DockPanel.Dock="Left" Margin="0, 2, 0, 2" Padding="0">
<Image Width="24"
Height="24"
Margin="2"
Source="{TemplateBinding Icon}"
SnapsToDevicePixels="True"
RenderOptions.EdgeMode="Aliased" />
<Run BaselineAlignment="Center"
Text="{TemplateBinding Title}"
Foreground="{DynamicResource DefaultBackgroundBrush}"/>
</TextBlock>
<TextBlock DockPanel.Dock="Right" HorizontalAlignment="Right">
<!--This it the part I showed before -->
<StackPanel Width="38" Height="32">
<StackPanel.Style>
<Style TargetType="StackPanel">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Green"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="False">
<Setter Property="Background" Value="Red"/>
</Trigger>
</Style.Triggers>
</Style>
</StackPanel.Style>
<Image
Width="38"
Height="32"
Margin="0"
Source="../Images/FrameControlIcons/38x32/close.png"/>
</StackPanel>
<!--/////////////////////-->
</TextBlock>
</DockPanel>
<DockPanel Grid.Column="1" Grid.Row="1" >
<ContentPresenter />
</DockPanel>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
My co-worker recognized the problem. The Problem was, that my Image was covered by the CaptionHeight of the WindowChrome. When i set the CaptionHeigt to zero it works.
So i found a solution to make both work. The CaptionHeight (To drag the window around) and the mouse event on Element that are coverd by the CaptionHeight.
I had to set this property on the affected element:
shell:WindowChrome.IsHitTestVisibleInChrome="True"
I found this Solution here:
How can I add a button to the WPF caption bar while using custom window chrome?

WPF StackPanel content vertical alignment

Is there a way in XAML to say that I want to center-align vertically all components inside a horizontal-oriented StackPanel?
I achieve the desired result with the below XAML:
<StackPanel Orientation="Horizontal">
<TextBlock VerticalAlignment="Center"/>
<Button VerticalAlignment="Center"/>
<TextBox VerticalAlignment="Center"/>
<Button VerticalAlignment="Center"/>
<TextBlock VerticalAlignment="Center"/>
</StackPanel>
But I need to repeat the VerticalAlignment="Center" for each control separately.
Is there a way to declare on the StackPanel level something like below?
<StackPanel Orientation="Horizontal" VERTICALCONTENTALIGNMENT="Center">
<TextBlock/>
<Button/>
<TextBox/>
<Button/>
<TextBlock/>
</StackPanel>
Put the StackPanel inside a Grid and set VerticalAlignment="Center" on the StackPanel
<Grid>
<StackPanel VerticalAlignment="Center">
...
</StackPanel
</Grid>
You can define style for StackPanel with Trigger which sets VerticalAlignment of all children:
<Style x:Key="HorizontalStackPanel" TargetType="{x:Type StackPanel}">
<Setter Property="Orientation" Value="Horizontal" />
<Style.Triggers>
<Trigger Property="Orientation" Value="Horizontal">
<Setter Property="FrameworkElement.VerticalAlignment" Value="Center" />
</Trigger>
</Style.Triggers>
</Style>
And apply this style:
<StackPanel Style="{StaticResource HorizontalStackPanel}">
<TextBlock />
<Button />
<TextBox />
<Button />
<TextBlock />
</StackPanel>
It works for me.
The whole code:
<Window x:Class="WpfApplication11.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Style x:Key="HorizontalStackPanel" TargetType="{x:Type StackPanel}">
<Setter Property="Orientation" Value="Horizontal" />
<Style.Triggers>
<Trigger Property="Orientation" Value="Horizontal">
<Setter Property="FrameworkElement.VerticalAlignment" Value="Center" />
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<StackPanel Style="{StaticResource HorizontalStackPanel}">
<TextBlock Text="One"/>
<Button Content="Two"/>
<TextBox Text="Three"/>
<Button Content="Four"/>
<TextBlock Text="Five"/>
</StackPanel>
</Grid>
</Window>
Define a style like this;
<Style x:Key="StackHorizontal" TargetType="StackPanel">
<Style.Resources>
<Style TargetType="TextBlock" BasedOn="{StaticResource {x:Type TextBlock}}">
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
<Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
</Style.Resources>
</Style>
Just use this:
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
<TextBlock/>
<Button/>
<TextBox/>
<Button/>
<TextBlock/>
</StackPanel>

WPF Resource Styles not showing first time

When I bind my collection to the following window and usercontrol, the styles do not work.
When I press a button on the window, the styles kick in.
What is stopping my styles from firing at initial bind?
<Grid>
<ItemsControl Name="LbItems" ItemsSource="{Binding MyData}">
<ItemsControl.Resources>
<DataTemplate DataType="{x:Type viewModel:SomeViewModel}">
<control:SomeView Margin="5" />
</DataTemplate>
<DataTemplate DataType="{x:Type viewModel:AnotherViewModel}">
<control:AnotherView Margin="5" />
</DataTemplate>
</ItemsControl.Resources>
</ItemsControl>
</Grid>
And I have a user control as follows:
<UserControl.Resources>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={x:Static
RelativeSource.Self}, Path=DataContext.Selected}" Value="False">
<Setter Property="Foreground">
<Setter.Value>
Red
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={x:Static
RelativeSource.Self}, Path=DataContext.Selected}" Value="True">
<Setter Property="Foreground">
<Setter.Value>
DarkSeaGreen
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Button Command="{Binding SelectCommand}" Content="+" HorizontalAlignment=
"Left" VerticalAlignment="Top" Width="25" Grid.Column="0"/>
<TextBlock HorizontalAlignment="Left" Margin="5" TextWrapping="Wrap" Text=
"{Binding Endorsement.Name}" VerticalAlignment="Top" Grid.Column="1" />
<Button Command="{Binding DeselectCommand}" Content="-" HorizontalAlignment=
"Right" VerticalAlignment="Top" Width="25" Grid.Column="2"/>
</Grid>
When the page loads and when the 'Selected' is set is two different times; hence selected is null when the page loads and nothing happens. Anticipate the null situation such as an added style
<DataTrigger Binding="{Binding RelativeSource={x:Static
RelativeSource.Self}, Path=DataContext.Selected}" Value="{x:Null}">
...
You shouldn't have to do this in your DataTrigger binding:
Binding="{Binding RelativeSource={x:Static
RelativeSource.Self}, Path=DataContext.Selected}"
A binding by default is referencing the DataContext so the equivalent simpler form is this:
Binding="{Binding Path=Selected}"
I don't think that will solve your problem though (but if it does that's great). One way around it is to define a default value in the style for your Foreground if neither trigger fires:
<UserControl.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="Red" />
<Style.Triggers>
...
This assumes that all your items are deselected upon load. Hope this helps.
Cheers,
Eric

WPF DevExpress LookUpEdit Popup Too High

I'm using a DevExpress LookUpEdit component in a WPF UserControl. My problem is that the popup rectangle is always much bigger that the contents of the items in the PopupContentTemplate. I can't seem to find a property that governs this or maybe I'm going about using the controls improperly (?).
Thanks
<UserControl xmlns:dxe="http://schemas.devexpress.com/winfx/2008/xaml/editors"
x:Class="FTI_Opp_WPF.Views.UserControls.ViewSelector"
xmlns:dxg="http://schemas.devexpress.com/winfx/2008/xaml/grid"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary
Source="../../Common/Styles.xaml" />
<ResourceDictionary
Source="../../Common/Strings.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" FontSize="12" Foreground="gray" Margin="0,-2,1,0">View:</Label>
<dxg:LookUpEdit
Grid.Column="1"
dx:ThemeManager.ThemeName="MetropolisLight"
Name="viewLookupEdit"
AutoPopulateColumns="False"
AutoComplete="True"
IncrementalFiltering="True"
ImmediatePopup="True"
IsReadOnly="True"
HorizontalAlignment="Right"
VerticalAlignment="Top"
Text="{Binding SelectedViewName}"
ShowSizeGrip="false"
MinWidth="200">
<dxg:LookUpEdit.PopupContentTemplate>
<ControlTemplate>
<StackPanel Orientation="Vertical" Height="auto">
<ListBox Name="lstMain"
ItemsSource="{Binding Path=GridViews}"
HorizontalAlignment="Stretch"
BorderThickness="1"
MouseUp="OnRowMouseUp">
<ListBox.ItemContainerStyle>
<Style
TargetType="{x:Type ListBoxItem}">
<Setter Property="BorderThickness">
<Setter.Value>1</Setter.Value>
</Setter>
<Setter
Property="Template">
<Setter.Value>
<ControlTemplate
TargetType="{x:Type ListBoxItem}">
<Grid Name="gridView" Height="25">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="14"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image Grid.Column="0"
Margin="0,-2,0,0"
Visibility="Visible"
Source="..\..\Images\globe.png"
Height="12"
Width="12" />
<TextBlock
Margin="2,3,0,0"
Grid.Column="1"
Name="viewName"
VerticalAlignment="Stretch"
Text="{Binding Path=Name}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger
Property="IsMouseOver"
Value="true">
<Setter
TargetName="gridView"
Property="Background" Value="{Binding Converter={StaticResource StyleConverter},ConverterParameter=HOVER_BACKGROUND_COLOR}">
</Setter>
<Setter
TargetName="viewName"
Property="Foreground" Value="White">
</Setter>
<Setter
TargetName="viewName"
Property="FontWeight" Value="BOLD">
</Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger
Binding="{Binding Path=IsEnabled}"
Value="False">
<Setter
Property="IsEnabled"
Value="{Binding Path=IsEnabled}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
<Button
Name="btnAdvanced"
Margin="10,0,0,0"
Style="{StaticResource Link}"
Content="manage views"
Click="OnManageViewsClick" />
</StackPanel>
</ControlTemplate>
</dxg:LookUpEdit.PopupContentTemplate>
</dxg:LookUpEdit>
</Grid>
</UserControl>
DX don't provide an "auto size to popup content" feature. You need to work with PopupMinHeight / PopupMaxHeight / PopupHeight.
See this link: http://www.devexpress.com/Support/Center/p/Q428449.aspx

WPF UserControl Focus

I have a UserControl subclass that contains a Grid, which in turn contains a couple TextBlocks and a Border (which also contains a TextBlock). See code below.
<UserControl x:Class="ProjectNS.MyUserControl"
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:my="clr-namespace:ProjectNS"
mc:Ignorable="d"
Height="49" Width="150" BottomResizeLocked="True" TopResizeLocked="True"
MoveLocks="Vertical" Margin="0,-4" Focusable="True">
<my:MyUserControl.Resources>
<Style x:Key="BorderStyle" TargetType="Border">
<Setter Property="Background" Value="Blue"/>
<Setter Property="BorderBrush" Value="Blue"/>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource
AncestorType={x:Type my:GanttBar}}, Path=IsKeyboardFocusWithin}"
Value="True">
<Setter Property="Background" Value="{StaticResource
SelectedGanttBarBackGroundBrush}"/>
<Setter Property="BorderBrush" Value="{StaticResource
SelectedGanttBarBorderBrush}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</my:MyUserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="2*" />
<RowDefinition Height="3*" />
<RowDefinition Height="2*" />
</Grid.RowDefinitions>
<Label FontSize="8.5" HorizontalAlignment="Left"
VerticalAlignment="Bottom" Margin="4,0,0,0" Foreground="Green" />
<Border Grid.Row="1" CornerRadius="5" BorderThickness="1.5" Style="
{StaticResource BorderStyle}" FocusVisualStyle="{StaticResource
SelectedBorderStyle}" Focusable="True" >
<Label FontSize="10" HorizontalAlignment="Center" FontWeight="Bold"
VerticalAlignment="Top" Foreground="White" Margin="0,2,0,0" />
</Border>
<Label HorizontalAlignment="Right" FontSize="8.5" Grid.Row="2"
VerticalAlignment="Top" Margin="0,0,4,0" Foreground="Red" />
</Grid>
</my:MyUserControl>
I'm trying to get the color of the embedded Border to change color when my UserControl receives focus, but I can't for the life of me figure out what actually receives focus when I click on the control. I've tried using the GotFocus event for every control, and nothing fires once the program is running.
Use a DataTrigger on the property IsKeyboardFocusWithin. I'm not positive the exact syntax, but it should look something like this:
<Style TargetType="{x:Type Border}">
<Setter Property="BorderBrush" Value="Red" />
<Style.Triggers>
<!-- Will change Border color when KeyboardFocus inside Border -->
<Trigger Property="IsKeyboardFocusWithin" Value="True">
<Setter Property="BorderBrush" Value="Green" />
</Trigger>
<!-- Will change Border color when UserControl contains KeyboardFocus -->
<DataTrigger Binding="{Binding RelativeSource={RelativeSource
AncestorType={x:Type local:MyUserControl}},
Path=IsKeyboardFocusWithin}" Value="True">
<Setter Property="BorderBrush" Value="Blue" />
</DataTrigger>
</Style.Triggers>
</Style>

Resources