Resizing only open expanders - wpf

I have 3 expanders in a window and I want to know if there is a way to have it so that if I have expander 2 and 3 open but not 1 it will only stretch those 2. It's current stretching all three equally. Also, when they are closed the content closes but the column stays the same width as if it was open.
What is the best way to get them to only stretch when expanded and go back to the small size of 10 pixels wide when collapsed?

You could set Triggers on the ColumnDefinitions to set the Width to Fixed when the Expander is closed and set to proportional when the Expander is open.
Example:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition>
<ColumnDefinition.Style>
<Style TargetType="ColumnDefinition">
<Setter Property="Width" Value="20" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsExpanded, ElementName=expander1}" Value="True">
<Setter Property="Width" Value="20*" />
</DataTrigger>
</Style.Triggers>
</Style>
</ColumnDefinition.Style>
</ColumnDefinition>
<ColumnDefinition>
<ColumnDefinition.Style>
<Style TargetType="ColumnDefinition">
<Setter Property="Width" Value="20" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsExpanded, ElementName=expander2}" Value="True">
<Setter Property="Width" Value="20*" />
</DataTrigger>
</Style.Triggers>
</Style>
</ColumnDefinition.Style>
</ColumnDefinition>
<ColumnDefinition>
<ColumnDefinition.Style>
<Style TargetType="ColumnDefinition">
<Setter Property="Width" Value="20" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsExpanded, ElementName=expander3}" Value="True">
<Setter Property="Width" Value="20*" />
</DataTrigger>
</Style.Triggers>
</Style>
</ColumnDefinition.Style>
</ColumnDefinition>
</Grid.ColumnDefinitions>
<Expander Name="expander1" Grid.Column="0" Header="Expander1" />
<Expander Name="expander2" Grid.Column="1" Header="Expander2" />
<Expander Name="expander3" Grid.Column="2" Header="Expander3" />
</Grid>
Result:

Related

WPF Data grid Background color of selected row

I want to set background color of the selected row. Please see the below code.
Foreground color (text color) is working but its not changing background color of row.
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Grid>
<ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="DataGridCell.IsSelected" Value="True">
<Setter Property="Foreground" Value="Blue" />
<Setter Property="Background" Value="Green" />
</Trigger>
</Style.Triggers>
</Style>
<DataGrid x:Name="Details" Grid.Column="1" Grid.Row="3" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10,10,10,10"
ItemsSource="{Binding Details}" >
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Index}" Header="Index" />
<DataGridTextColumn Binding="{Binding One}" Header="1" />
<DataGridTextColumn Binding="{Binding two}" Header="2" />
<DataGridTextColumn Binding="{Binding three}" Header="3" />
</DataGrid.Columns>
</DataGrid>
Now issue is solved after adding specific style for row itself. It was not working when i added for cell.
<Style TargetType="{x:Type DataGridRow}">
<Style.Triggers>
<Trigger Property="DataGridRow.IsSelected" Value="True">
<Setter Property="Foreground" Value="Blue" />
<Setter Property="Background" Value="Green" />
</Trigger>
</Style.Triggers>
</Style>

Fill button into a datagrid cell

I have a data grid and for the column HCode I have/need buttons, but the property Code can be null/empty in which case the Button will not be visible.
I'd like to know if there are options or defining a mouse-click handler for the cell is the way to go.
Below is the DataGridTemplate defining the column
<DataGridTemplateColumn Header="HCode" MinWidth="120">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="{Binding Code}"
Style="{StaticResource BStyle}"
Background="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=TextBlock}, Path=Background}"
Click="ButtonBase_OnClick"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Center"
/>
<!--Visibility="{qc:Binding '$P != null && $P.Length > 0 ? Visibility.Visible : Visibility.Collapsed', P={Binding Code}}"-->
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
Below is the style that is used
<Style x:Key="BStyle"
TargetType="{x:Type Button}">
<Setter Property="SnapsToDevicePixels"
Value="true" />
<Setter Property="BorderThickness"
Value="0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30*"></RowDefinition>
</Grid.RowDefinitions>
<ContentPresenter Margin="0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
RecognizesAccessKey="True" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Foreground"
Value="Blue" />
<Style.Triggers>
<Trigger Property="IsMouseOver"
Value="true">
<Setter Property="Foreground"
Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
You could define two DataTriggers. Try this:
<Button Content="{Binding Code}"
Background="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=TextBlock}, Path=Background}"
Click="ButtonBase_OnClick"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Center">
<Button.Style>
<Style TargetType="Button" BasedOn="{StaticResource BStyle}">
<Style.Triggers>
<DataTrigger Binding="{Binding Code}" Value="{x:Null}">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
<DataTrigger Binding="{Binding Code.Length}" Value="0">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
Or:
<DataTrigger Binding="{Binding Code.Length, FallbackValue=0}" Value="0">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>

How to trap button click event inside listbox item template

I have listbox with textbox inside to display list items. I want to have editable textbox , So I put button inside listbox for selected textbox. I want to trigger button click event for that listbox but I couldn't. Here is my code:
<ListBox HorizontalAlignment="Left" Name="ListTwo" Height="auto" Margin="134.53,15.934,0,0" VerticalAlignment="Top" Width="202.308" ItemsSource="{Binding . ,Source=CollectionUrl,BindsDirectlyToSource=True}" BorderThickness="0" >
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
<RadioButton>
<TextBox Name="TextBoxList" Text="{Binding Path=urlString, Mode=TwoWay}" Width="150">
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="IsFocused" Value="True">
<Setter Property="Foreground" Value="Black"/>
<Setter Property="IsReadOnly" Value="False" />
<Setter Property="BorderThickness" Value="0.5"/>
</Trigger>
<Trigger Property="IsFocused" Value="False">
<Setter Property="Foreground" Value="Gray"/>
<Setter Property="IsReadOnly" Value="True" />
<Setter Property="BorderThickness" Value="0"/>
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</RadioButton>
<Button Content="Save" Grid.Column="1" Tag="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ListBox}}" Click="Button_Click_2">
<Button.Style>
<Style TargetType="Button">
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=TextBoxList, Path=IsFocused}" Value="True">
<Setter Property="Visibility" Value="Visible" />
<Setter Property="ClickMode" Value="Press"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Anyone knows how can I trap click event of button?
Did you try adding an event for Button in the ListBox. This will capture the event.
Button.Click="OnClick"
So like this:
<ListBox HorizontalAlignment="Left" Name="ListTwo" Height="auto" Margin="134.53,15.934,0,0" VerticalAlignment="Top" Width="202.308" ItemsSource="{Binding . ,Source=CollectionUrl,BindsDirectlyToSource=True}" BorderThickness="0" Button.Click="OnClick">
Then your event:
private void OnClick(object sender, RoutedEventArgs e)
{
var originalSource = e.OriginalSource;
// Do your work here
}
However, you have a second problem. Your button style is preventing your event from firing. It works without the style but doesn't fire with the style. Change the style to be on ListBoxItem.IsSelected. Then make it so if you select a TextBox the ListBoxItem is selected.
<ListBox HorizontalAlignment="Left" Name="ListTwo" Height="auto" Margin="134.53,15.934,0,0" VerticalAlignment="Top" Width="202.308" ItemsSource="{Binding . ,Source=CollectionUrl,BindsDirectlyToSource=True}" BorderThickness="0" Button.Click="OnClick">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
<RadioButton>
<TextBox Name="TextBoxList" Text="{Binding Path=urlString, Mode=TwoWay}" Width="150">
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="IsFocused" Value="True">
<Setter Property="Foreground" Value="Black"/>
<Setter Property="IsReadOnly" Value="False" />
<Setter Property="BorderThickness" Value="0.5"/>
</Trigger>
<Trigger Property="IsFocused" Value="False">
<Setter Property="Foreground" Value="Gray"/>
<Setter Property="IsReadOnly" Value="True" />
<Setter Property="BorderThickness" Value="0"/>
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</RadioButton>
<Button Content="Save" Grid.Column="1">
<Button.Style>
<Style TargetType="Button">
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}, Path=IsSelected}" Value="True">
<Setter Property="Visibility" Value="Visible" />
<Setter Property="ClickMode" Value="Press"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsKeyboardFocusWithin, RelativeSource={RelativeSource Self}}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="(ListBoxItem.IsSelected)">
<DiscreteBooleanKeyFrame KeyTime="0" Value="True"/>
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
Hope that helps.
You have several options to do it but I'll just give you the two best ones without using third party frameworks.
First is through System.Windows.Interactions and put it inside the TextBox. This will be handled in your ViewModel
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click" >
<i:InvokeCommandAction Command="{Binding ClickCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
Second is through using EventSetter, this will be handled behind the View
<Style TargetType="ListBoxItem">
<EventSetter Event="MouseDoubleClick" Handler="TextBoxClick"/>
</Style>

WPF Mouseover Trigger Effect for Child Controls

Lets say I have this bit of code:
<Window>
<Window.Resources>
<Color x:Key="MyColor"
A="255"
R="152"
G="152"
B="152" />
<DropShadowEffect x:Key="MyEffect"
ShadowDepth="0"
Color="{StaticResource MyColor}"
BlurRadius="10" />
<Style x:Key="MyGridStyle"
TargetType="{x:Type Grid}">
<Setter Property="Height"
Value="200" />
<Setter Property="Width"
Value="200" />
<Style.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Width"
Value="100" />
</Style>
<Style TargetType="{x:Type Image}">
<Setter Property="Height"
Value="100" />
<Setter Property="Width"
Value="100" />
</Style>
</Style.Resources>
<Style.Triggers>
<Trigger Property="IsMouseOver"
Value="true">
<!-- How do I apply my effect when this grid is hovered over to Image and TextBox, but not the grid itself? -->
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid Style="{StaticResource MyGridStyle}">
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Image Grid.Row="0"
Grid.Column="0"
Source="image.png" />
<TextBlock Grid.Row="0"
Grid.Column="0"
Text="Hover Over Me" />
</Grid>
</Window>
Basically I have a Style applied to the Grid that says any TextBlock or Image within it should be styles to a certain size.
I want to create a Trigger on the Grid that causes an effect to be applied to all TextBlocks and Images within the Grid, but not to the Grid itself.
I can apply the Trigger directly to TextBlock and/or Image, but then the effect only occurs on each element separately. I need to have the effect occur to any TextBlock and/or Image within the Grid despite which inner child element I am hovered over.
Can anyone help me with this?
You can do it the other way around. That is, add DataTriggers to Image and TextBlock and make them trigger on IsMouseOver for the ancestor Grid.
Note: If you want this effect to trigger as soon as the mouse is over the Grid you will need to set Background to a value, like Transparent. By default, the Background is null and this value isn't used in hit testing.
<Style x:Key="MyGridStyle" TargetType="{x:Type Grid}">
<!--<Setter Property="Background" Value="Transparent"/>-->
<Setter Property="Height" Value="200" />
<Setter Property="Width" Value="200" />
<Style.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Width" Value="200" />
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Grid},
Path=IsMouseOver}" Value="True">
<Setter Property="Effect" Value="{StaticResource MyEffect}"/>
</DataTrigger>
</Style.Triggers>
</Style>
<Style TargetType="{x:Type Image}">
<Setter Property="Height" Value="200" />
<Setter Property="Width" Value="200" />
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Grid},
Path=IsMouseOver}" Value="True">
<Setter Property="Effect" Value="{StaticResource MyEffect}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Style.Resources>
</Style>
We once had a similar requirement of outer glowing ONLY the content of a row of a list box, not the row overall. We took help of this article... http://drwpf.com/blog/2008/03/25/itemscontrol-i-is-for-item-container.

WPF switch between regions with toggle button

I have a view, that when loaded contains a toolbar at the top, and two regions underneath.
I am currently using a grid, so:
row 0 contains the toolbar
row 1 contains region1 and
row 2 contains region2.
The toolbar has a toggle button, which when clicked, completely hides region1, and shows region 2, and visa-versa.
What is the best way to achieve this?
I have tried binding the 2 rows heights to get altered on the toggle, but the space is not filled correctly. VerticalAlignment="Stretch" and HorizontalAlignment="Stretch" are both used.
I have also tried enabling and disabling the itemcontrol hosting the region, but that doesn't seem to work at all.
Any pointers as to what I have done are much appreciated! :)
Not sure if I fully understand what you want. Something like this?
<DockPanel>
<ToggleButton Name="viewToggle" DockPanel.Dock="Top">Toggle Region</ToggleButton>
<Grid>
<ContentControl>
<TextBlock>I'm region 1</TextBlock>
<ContentControl.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=viewToggle, Path=IsChecked}" Value="False">
<Setter Property="ContentControl.Visibility" Value="Visible"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=viewToggle, Path=IsChecked}" Value="True">
<Setter Property="ContentControl.Visibility" Value="Hidden"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
<ContentControl>
<TextBlock>I'm region 2</TextBlock>
<ContentControl.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=viewToggle, Path=IsChecked}" Value="True">
<Setter Property="ContentControl.Visibility" Value="Visible"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=viewToggle, Path=IsChecked}" Value="False">
<Setter Property="ContentControl.Visibility" Value="Hidden"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</Grid>
</DockPanel>
I used for this one row that contains region1 and region2 too. region2's Visibility set to Collapsed by default, and when an event occured (a checkbox for me, databound to a bool value) i flipped the Visibility of the regions. My 'regions' contained two different layout, and i don't experienced any issue.
A quick sample code without code-behind:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.Resources>
<Style x:Key="showOnToggled" TargetType="GroupBox" BasedOn="{StaticResource {x:Type GroupBox}}" >
<Setter Property="Visibility" Value="Visible" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=toggleButton, Path=IsChecked}" Value="True" >
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
<Style x:Key="hideOnToggled" TargetType="GroupBox" BasedOn="{StaticResource {x:Type GroupBox}}" >
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=toggleButton, Path=IsChecked}" Value="True" >
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Resources>
<ToggleButton Content="Switch Region"
Grid.Row="0"
x:Name="toggleButton" />
<GroupBox Header="Region1"
Grid.Row="1"
Style="{StaticResource showOnToggled}" >
<!-- Region1's content -->
</GroupBox>
<GroupBox Header="Region2"
Grid.Row="1"
Style="{StaticResource hideOnToggled}" >
<!-- Region2's content -->
</GroupBox>
</Grid>

Resources