Very weird logical error in WPF GridViewColumnHeader - wpf

I have custom treelistview and I put a checkbox in the first column of my treelistview. everything is ok but when I want to hide the checkbox column for other purpose (using variable SelectEnable) , it does not hide correctly(it hides but a blank area remains). This Problem happens when I load the data (I mean when treelistview is empty, the column is hidden).
here is some pieces of my xaml:
<Style x:Key="checkboxColumnStyle"
TargetType="GridViewColumnHeader">
<Setter Property="Width"
Value="0" />
<Setter Property="Visibility"
Value="Hidden" />
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=SelectEnable}"
Value="False">
<Setter Property="Visibility"
Value="Hidden" />
<Setter Property="Width"
Value="0" />
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=SelectEnable}"
Value="True">
<Setter Property="Visibility"
Value="Visible" />
<Setter Property="Width"
Value="30" />
</DataTrigger>
</Style.Triggers>
</Style>
<DataTemplate x:Key="CellTemplate_checkBox">
<CheckBox IsChecked="{Binding IsSelected}"
VerticalAlignment="Center"
Style="{DynamicResource checkboxStyle}"
Tag="{Binding}"
Checked="CheckBox_Checked"
Unchecked="CheckBox_Checked" />
</DataTemplate>
<GridViewColumnCollection x:Key="gvcc">
<GridViewColumn CellTemplate="{StaticResource CellTemplate_checkBox}">
<GridViewColumnHeader Style="{DynamicResource checkboxColumnStyle}"
MaxWidth="0">
<CheckBox x:Name="chechBoxAll"
Style="{DynamicResource checkboxStyle}"
Checked="chechBoxAll_Checked"
Unchecked="chechBoxAll_Checked" />
</GridViewColumnHeader>
</GridViewColumn>
<!--Other Columns -->
</GridViewColumnCollection>
How can i fix this?

You probably want Visibility.Collapsed instead of Visibility.Hidden.
Hidden means the element is there but cannot be seen (similar to Opacity of 0), whereas Collapsed causes the layout arrangement to happen as though the element does not exist (no width and no height).

Related

Editable WPF ListBox contains textbox

I want to have dynamic editable listbox in wpf application. I am using textbox inside listbox, and I am binding Observable collection to that listbox. Now, I want to make textbox editable on mouse click. So, user can make change to textbox and save new textbox text.
<ListBox Name="ListTwo" ItemsSource="{Binding CollectionUrl, Mode=TwoWay}" >
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Name="TextBoxList" Text="{Binding Path=urlString}" IsEnabled="False" >
</TextBox>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
You should use IsReadOnly property. In the trigger you should check IsFocused property.
In the following example, I changed foreground color to indicate which TextBox is in the edit mode.
Example:
<ListBox Name="ListTwo" ItemsSource="{Binding CollectionUrl, Mode=TwoWay}" >
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Name="TextBoxList" Text="{Binding Path=urlString}" MinWidth="100">
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="IsFocused" Value="True">
<Setter Property="Foreground" Value="Green"/>
<Setter Property="IsReadOnly" Value="False" />
</Trigger>
<Trigger Property="IsFocused" Value="False">
<Setter Property="Foreground" Value="Red"/>
<Setter Property="IsReadOnly" Value="True" />
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
If you want to allow users save changes after edit value in the TextBox, you can add button and show in the actual editing row:
<ListBox Name="ListTwo" ItemsSource="{Binding CollectionUrl, Mode=TwoWay}" >
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
<TextBox Name="TextBoxList" Text="{Binding Path=urlString}" MinWidth="100">
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="IsFocused" Value="True">
<Setter Property="Foreground" Value="Green"/>
<Setter Property="IsReadOnly" Value="False" />
</Trigger>
<Trigger Property="IsFocused" Value="False">
<Setter Property="Foreground" Value="Red"/>
<Setter Property="IsReadOnly" Value="True" />
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
<Button Content="Save" Grid.Column="1" Command="{Binding SaveChanges}">
<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" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
My approach to accessing the text box (which was proving a nightmare) was to use your save button approach and in the Button's Button_Click function I used sender to retrieve the Button's parent, cast to (in your case) Grid. Then you can use that to access the Grid's Children with .Children[0] being your TextBox.
Bit of a Kluge because your code has to 'know' the type of the parent and the index of the child TextBox but these will not change. If necessary the purists can iterate through the Children to identify the required child explicitly.
Hope this helps someone.

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>

Change WPF StackPanel background color when an element in the panel has focus

If I have a set of controls within a StackPanel, is there a generic way to change the background of the stackpanel when any control within the StackPanel gains focus? (and obviously switch the background back when no control in the StackPanel has focus). The following code works for me, but it would be nice to have a generic way to accomplish this task versus having to list each control in every StackPanel in my page.
Thanks!
<StackPanel Margin="5">
<StackPanel.Style>
<Style TargetType="{x:Type StackPanel}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsFocused, ElementName=chkOccupiedByMortgagor}" Value="true">
<Setter Property="Background" Value="Gray" />
<Setter Property="Opacity" Value=".5" />
</DataTrigger>
<DataTrigger Binding="{Binding IsFocused, ElementName=chkOccupiedByNewOwner}" Value="true">
<Setter Property="Background" Value="Gray" />
<Setter Property="Opacity" Value=".5" />
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Style>
<CheckBox Margin="2" x:Name="chkOccupiedByMortgagor">Mortgagor</CheckBox>
<CheckBox Margin="2" x:Name="chkOccupiedByNewOwner">New Owner</CheckBox>
<CheckBox Margin="2" x:Name="chkOccupiedByTenant">Tenant</CheckBox>
<CheckBox Margin="2" x:Name="chkOccupiedByUnknownOccupant">Unknown Occupant</CheckBox>
</StackPanel>
Yes. You can do that. Just use IsKeyboardFocusWithin property for the trigger, like this:
<StackPanel Margin="5">
<StackPanel.Style>
<Style TargetType="{x:Type StackPanel}">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsKeyboardFocusWithin}" Value="True">
<Setter Property="Background" Value="Gray" />
<Setter Property="Opacity" Value=".5" />
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Style>
<CheckBox Margin="2">Mortgagor</CheckBox>
<CheckBox Margin="2">New Owner</CheckBox>
<CheckBox Margin="2">Tenant</CheckBox>
<CheckBox Margin="2">Unknown Occupant</CheckBox>
</StackPanel>
Do remember though, that you need to tell the trigger to look for the property in the same element, hence, RelativeSource={RelativeSource Self}. Alternatively, you can name the stack panel and use this xaml too:
<StackPanel Margin="5" x:Name="stackPanel">
...
<DataTrigger Binding="{Binding ElementName=stackPanel, Path=IsKeyboardFocusWithin}" Value="True">
...

WPF Listbox - Empty List Display Message

Can anyone suggest the best way to display a Textblock (with a text such as "List Empty") so that it's visibility is bound to the Items.Count.
I have tried the following code and can't get it to work, so think that I must be doing it wrong.
<ListBox x:Name="lstItems"
ItemsSource="{Binding ListItems}">
</ListBox>
<TextBlock Margin="4" FontStyle="Italic" FontSize="12" Text="List is empty" Visibility="Collapsed">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=lstItems, Path=Items.Count}" Value="0">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
The problem in your code is that setting the value of Visibility in the text block itself has higher priority than setting it in the style. So, even when the trigger occurs, the setting inside the trigger has no effect. Change the XAML to:
<TextBlock Margin="4" FontStyle="Italic" FontSize="12" Text="List is empty" >
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=lstItems, Path=Items.Count}" Value="0">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
Where the setting of Visibility is all in the style and it works (at least in my demo project).

How can I "Click Through" a control in WPF?

I have an order entry form that has a ListBox with a list of line items. I have my items template, and one of the values is a ComboBox in each of my Items.
Now, my form can also create Credit memo's in addition to purchase orders, but when I am creating a credit memo, I want to put the words "Credit Memo" over the list box, however, the TextBlock covers the ComboBox in two of my line items. I would like to pass my click event through the TextBlock to the ComboBoxes but I'm not sure how to do it.
This is what I have, ( Maybe I am coming at this totally wrong, I am kinda a noob with WPF )
<ListBox SelectionMode="Single" Grid.Row="2"
ItemsSource="{Binding Path=LineItems}" HorizontalContentAlignment="Stretch"
IsSynchronizedWithCurrentItem="True" Background="#66FFFFFF">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Background" Value="WhiteSmoke"/>
<Setter Property="BorderThickness" Value="1" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsPartBackOrder}" Value="True">
<Setter Property="Background" Value="Orange" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type Entities:SalesOrderLineItem}" >
<OrderEntry:SalesOrderLineItemCreate DataContext="{Binding}" DeleteSalesOrderLineItem="DeleteSalesOrderLineItem" Margin="0,3,3,0" >
<OrderEntry:SalesOrderLineItemCreate.Resources>
<Style TargetType="{x:Type OrderEntry:SalesOrderLineItemCreate}">
<Style.Triggers>
<DataTrigger
Binding="{Binding RelativeSource=
{
RelativeSource
Mode=FindAncestor,
AncestorType={x:Type ListBoxItem}
},
Path=IsSelected
}" Value="True">
<Setter Property="Background" Value="LightBlue" />
<Setter Property="Foreground" Value="Black" />
</DataTrigger>
</Style.Triggers>
</Style>
</OrderEntry:SalesOrderLineItemCreate.Resources>
</OrderEntry:SalesOrderLineItemCreate>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<TextBlock Grid.Row="2"
Text="Credit Memo"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="48" Height="Auto"
FontStyle="Italic"
Foreground="Red"
Opacity=".25">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=OrderType}" Value="CR">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=OrderType}" Value="CU">
<Setter Property="Visibility" Value="Hidden" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
<TextBlock IsHitTestVisible="False" .../>

Resources