Is it possible to hide a checkbox, but leave its content visible?
<ListBox
ItemsSource ="{Binding MyItemCollection}"
SelectionMode="Single"
Width="300"
Height="320">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsChecked}">
<CheckBox.Content>
<TextBlock Text="{Binding Item.Code}"/>
</CheckBox.Content>
</CheckBox>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<StackPanel>
<CheckBox Content="Edit Mode"
IsChecked="{Binding Path=EditModeSelected, Mode=TwoWay}">
</CheckBox>
</StackPanel>
I would like to hide the checkboxes in the list box when I turn Edit Mode off (so it should be binded to EditModeSelected), but the text should be left visible.
In order to do so You can keep two TextBlocks. In edit mode visible CheckBox and hide TextBlock and in reader mode vice versa. I hope this may help. As DataTemplate can have only one child here's the fix
Create a Window Resource like below. Two Data Templates were created one for edit mode and another for Reader Mode.
<Window.Resources>
<DataTemplate x:Key="EditModeTemplate">
<CheckBox IsChecked="{Binding IsChecked}">
<CheckBox.Content>
<TextBlock Text="{Binding Item.Code}"/>
</CheckBox.Content>
</CheckBox>
</DataTemplate>
<DataTemplate x:Key="ReaderModeTemplate">
<TextBlock Text="{Binding Item.Code}"/>
</DataTemplate>
</Window.Resources>
Now in .cs file assign the Date Template as per requirements.
if (EditMode)
{
DemoCollection.ItemTemplate = this.Resources["EditModeTemplate"] as DataTemplate;
}
else
{
DemoCollection.ItemTemplate = this.Resources["ReaderModeTemplate"] as DataTemplate;
}
3 possible solutions come in my mind - two of them more or less "hacks" and one more or less clean solution:
A checkbox and textblock for every item - you can get problems with margins etc
A checkbox with no content (which is only visible when in edit mode), and a textblock which is always visible
Take the default controltemplate for checkbox (Default ControlTemplate for CheckBox) and bind the visibility of the checkbox
Here is a Xaml only solution pulled from a project I am working on. In this case "ShowCheck" is a field in the current binding context saying whether or not to show the check.
<CheckBox Content="{Binding Name}">
<CheckBox.Style>
<Style TargetType="CheckBox">
<Style.Triggers>
<DataTrigger Binding="{Binding ShowCheck}" Value="False">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="CheckBox">
<ContentControl Content="{TemplateBinding Content}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</CheckBox.Style>
</CheckBox>
Basically if the checkbox should be invisible, then I use a style and a trigger to change the checkbox's template to something without the checkbox. My implementation the content is just a string, so this works. If you were putting more complicated objects into the checkbox, you might need to shuttle the ContentTemplate, ContentTemplateSelector, and related fields into the ContentControl that is used to replace the checkbox
Related
I have a ListBox with its ItemsSource bound to some UserControl-s and shown based on their current states(IsVisible)
Here is the code
<ListBox x:Name="sidebarList" Margin="0,0,10,10" ItemsSource="{Binding Modules, Mode=TwoWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0 5 0 5" Visibility="{Binding IsVisible, Mode=TwoWay}">
<TextBlock Text="{Binding Title}" FontWeight="Bold" />
<TextBlock Margin="0 5 0 0" MaxWidth="200" Foreground="Gray" Text="{Binding Detail}"
TextWrapping="WrapWithOverflow">
</TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsVisible}" Value="Collapsed">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
And now I'm trying to only get "IsVisible"/selected parts when a button is pressed. As of right now, the ListBox actually contains every option but just showing the IsVisible ones(at least that's what I think).
How do I only get the selected options? I have tried to use a new List with the same type as the UserControl-s type(which I placed in app.xaml.cs to call from anywhere) and add to that list when their state changes to IsVisible
but the List doesn't show up in my classes where I check them.
Sounds like what you really need is a view-model. Bind your Listbox to a view model that has an observable collection that only shows view-models of the items you want to present.
I can give you a more "correct" answer about how to do it with style/data-triggers but you should really just learn about MVVM and use a view-model to simplify.
I have a ListView bound with an ObservableCollection. The Itemtemplate of the ListView is the following:
<ListView ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True" PreviewMouseLeftButtonUp="ListViewClicked" PreviewKeyDown="NameBox_KeyDown">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="./Resources/DeleteIcon.png"/>
<TextBox Text="{Binding Path=Name}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
This way I give the user the choice to either change the name of the element, or delete it from the list. I handle this two operations in code behind through the two event handlers attached to the ListView.
The problem is that when I click on the TextBox, the SelectedItems property of the ListView doesn't change and it points the last selected item. When I click on the image or on the free space around the selection change.
Now I have two questions:
Is there an easy way to fix this behavior?
Is it possible to get a reference to the collection item whose property is exposed by the TextBox?
One way to deal with this problem is to set Trigger to set IsSelected when keyboard focus is within ListViewItem
<ListView ... SelectionMode="Single">
<!-- .... -->
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Style.Triggers>
<Trigger Property="IsKeyboardFocusWithin" Value="True">
<Setter Property="IsSelected" Value="True"/>
</Trigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
</ListView>
I have a dialog in my WPF application which contains a ListBox. The ListBox uses the following DataTemplate to display its contents:
<DataTemplate x:Key="AlarmClassTemplate">
<CheckBox Content="{Binding Path=Value}"
IsChecked="{Binding IsChecked}" />
</DataTemplate>
I've also configured the following template and style to display when there is an error in the ListBox's contents:
<ControlTemplate x:Key="InputErrorTemplateA">
<DockPanel LastChildFill="True">
<Image DockPanel.Dock="Right"
Height="30"
Margin="5"
Source="{StaticResource ErrorImage}"
ToolTip="Contains invalid data"
VerticalAlignment="Center"
Width="30" />
<Border BorderBrush="Red"
BorderThickness="5"
Margin="5">
<AdornedElementPlaceholder />
</Border>
</DockPanel>
</ControlTemplate>
<Style TargetType="{x:Type ListBox}">
<Setter Property="Validation.ErrorTemplate" Value="{StaticResource InputErrorTemplateA}" />
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="ToolTip">
<Setter.Value>
<Binding Path="(Validation.Errors).CurrentItem.ErrorContent" RelativeSource="{x:Static RelativeSource.Self}" />
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
And here's the XAML for the ListBox itself:
<ListBox FontSize="20"
FontWeight="Bold"
Grid.Column="1"
Grid.ColumnSpan="2"
Grid.Row="1"
Height="158"
ItemsSource="{Binding Path=IDs, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"
ItemTemplate="{StaticResource AlarmClassTemplate}"
Margin="5,0,110,0"
Name="AlarmClassListBox"
ToolTip="{x:Static res:Car.EditDataRetention_AlarmClasses_ToolTip}"
Visibility="{Binding Converter={StaticResource BoolToVisibility}, Path=DataTypeIsAlarms}" />
The validation logic for the data in the ListBox is that at least one item has to be checked off. If none of them are, the ListBox should display an error and the OK button on the dialog should be disabled.
The good news is that the OK button on the dialog is indeed disabled when nothing in the ListBox is checked. The bad news is that the Style doesn't seem to be working, in that no red border is displayed around the ListBox and the error image (a red circle with a white exclamation point inside) does not show.
I'm using the same exact ControlTempate and a similar Style on other controls on the same dialog and they work fine. What am I doing wrong? Is it the ListBox? Does ListBox validation work differently?
Indeed the problem is you weren't raising PropertyChanged event for your validation to gets fired.
But i can see one more issue in your code. You have set local value for tooltip on ListBox here:
ToolTip="{x:Static res:Car.EditDataRetention_AlarmClasses_ToolTip}"
But you want different tooltip in case validation returns some error which you define in style triggers.
But, local value has higher precedence order than style triggers. So, your tooltip will never be set. So, you should move the tooltip to style setters to work:
<Setter Property="ToolTip"
Value="{x:Static res:Car.EditDataRetention_AlarmClasses_ToolTip}"/>
MSDN link - Dependency property value precedence.
I found the answer to my problem in this post. It turns out that I have to raise the PropertyChanged event when the checkboxes change in order for the Validation logic to fire. Since the items in the ListBox implement INotifyPropertyChanged, it was easy to add an event listener for each item as it's added to the ListBox which raises the necessary event.
Thanks anyway.
I have ComboBox with custom ItemTemplate.
<ComboBox Height="20" Width="200"
SelectedItem="{Binding Path=SelectedDesign}"
ItemsSource="{Binding Path=Designs}" HorizontalAlignment="Left"
ScrollViewer.CanContentScroll="False">
<ComboBox.ItemTemplate>
<DataTemplate DataType="{x:Type formdesign:FormDesignContainer}">
<Rectangle Width="200" Height="100">
<Rectangle.Fill>
<ImageBrush ImageSource="{Binding Path=ImageThumb}" Stretch="Uniform" />
</Rectangle.Fill>
</Rectangle>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
This works well. However WPF tries to draw rectangle as Combobox Text. How can I set "text" for this template. By "text" I mean string or control which represent selected item and write into combobox when item is selected
In other words I'd like to do this:
But now I got this
Try setting SelectionBoxItemTemplate with a TextBlock.
Appears that SelectionBoxItemTemplate is read-only. So another approach is to override ItemContainerStyle.Template. Example
I found this solution by Ray Burns a good approach. You can define two DataTemplate one for Items in the drop down list and the other for the selected item which should be shown in the Combobox. The using a trigger and checking the visual tree it decide which one to use.
<Window.Resources>
<DataTemplate x:Key="NormalItemTemplate" ...>
...
</DataTemplate>
<DataTemplate x:Key="SelectionBoxTemplate" ...>
...
</DataTemplate>
<DataTemplate x:Key="CombinedTemplate">
<ContentPresenter x:Name="Presenter"
Content="{Binding}"
ContentTemplate="{StaticResource NormalItemTemplate}" />
<DataTemplate.Triggers>
<DataTrigger
Binding="{Binding RelativeSource={RelativeSource FindAncestor,ComboBoxItem,1}}"
Value="{x:Null}">
<Setter TargetName="Presenter" Property="ContentTemplate"
Value="{StaticResource SelectionBoxTemplate}" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</Window.Resources>
...
<ComboBox
ItemTemplate="{StaticResource CombinedTemplate}"
ItemsSource="..."/>
Add Textblock to the datatemplate and bind it
or add Contentpersenter on the rectangle
Edit:
it seems like i didn't got what you were tring to accomplish ,
I have a WPF checkbox list containing car models. When I tab into the list the follwoing happens:
1) On first tab key press, the list item is selected
2) On second tab key press, the actual checkbox is selected allowing me to set the IsChecked state using the spacebar key.
Is it possible to automatically move the cursor to the checkbox when the list item is selected? (trying to avoid hitting tab twice)
XAML:
<ListBox ItemsSource="{Binding Cars}">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Make}" IsChecked="{Binding IsChecked,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Try adding this to your ListBox:
<ListBox.ItemContainerStyle>
<Style TargetType="Control">
<Setter Property="Focusable" Value="False" />
</Style>
</ListBox.ItemContainerStyle>
Tried Dan's solution, it works but it moves the focus out of the ListBox control after selecting the first checkbox, I was looking for something which prevents the focus from being set to the selected listbox item while still allowing to tab through all the checkboxes in the list.
The following link helped me - Keyboard focus to list box items in WPF
I've made a few changes to have create border as well as the verticall scrollbar, complete XAML below:
<Border BorderThickness="0.8" BorderBrush="Gray">
<ScrollViewer ScrollViewer.VerticalScrollBarVisibility="Auto" Margin="1">
<ItemsControl ItemsSource="{Binding Cars}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Make}" IsChecked="{Binding IsChecked,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Border>