How can I know if item is selected inside the ItemTemplate? - c#

I have a ListBox that use my custom ItemTemplate. I want to set Visibility property in my TextBlock (inside my template) depending on selected item. I think of doing it using triggers. But how can I know inside my template if current item is selected or not?
<DataTemplate x:Key="myTemplate">
<StackPanel Orientation="Horizontal">
<Image Tag="{Binding priority}" Loaded="SetIconPriority"/>
<Image Tag="{Binding alarm}" Loaded="SetIconAlarm"/>
<!-- I want this TextBlock to be visible only when item is selected -->
<TextBlock Text="{Binding description}"/>
</StackPanel>
</DataTemplate>
edit:
It works, thanks! Code:
<TextBlock Grid.Column="2" Grid.Row="1" Text="{Binding opis}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=ListBoxItem}}" Value="False">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>

Using a RelativeSource binding with AncestorType being ListBoxItem.
<DataTrigger Binding="{Binding IsSelected,
RelativeSource={RelativeSource AncestorType=ListBoxItem}}"
Value="True">
(May want to reverse the logic and Collapse on False instead, avoids the default value Setter)

Related

ToolTip to show validation errors works for TextBlock bound to POCO but not Property within POCO. Why?

In my WPF MVVM project I use INotifyDataErrorinfo to handle validation within a DataGrid. I can successfully style error cells in my "Operator" column thus:
<DataGridTemplateColumn Header="Operator" Width="140">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Operator}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding OperatorId, Converter={StaticResource IsOperatorIdNullConverter}}" Value="False">
<Setter Property="FontWeight" Value="Bold"/>
</DataTrigger>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip">
<Setter.Value>
<ToolTip DataContext="{Binding RelativeSource={RelativeSource Self}, Path=PlacementTarget}">
<ItemsControl ItemsSource="{Binding Path=(Validation.Errors)}" DisplayMemberPath="ErrorContent"/>
</ToolTip>
</Setter.Value>
</Setter>
<Setter Property="Background" Value="Salmon"/>
</Trigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<Grid>
<controls:AutoCompleteBox Text="{Binding Operator, UpdateSourceTrigger=LostFocus, Mode=TwoWay}"
ItemsSource="{Binding Path=Data.OperatorNames, Source={StaticResource proxy}}"
IsTextCompletionEnabled="True"
FilterMode="Contains"
MinimumPrefixLength="3"/>
</Grid>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
In my "OperatorType" column however this same technique doesn't work. Errors are being detected and the system default error styling is shown but my custom styling isn't. The code is:
<DataGridTemplateColumn Header="Operator type" Width="140">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding OperatorType.OperatorTypeName}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip">
<Setter.Value>
<ToolTip DataContext="{Binding RelativeSource={RelativeSource Self}, Path=PlacementTarget}">
<ItemsControl ItemsSource="{Binding Path=(Validation.Errors)}" DisplayMemberPath="ErrorContent"/>
</ToolTip>
</Setter.Value>
</Setter>
<Setter Property="Background" Value="Salmon"/>
</Trigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<Grid>
<controls:AutoCompleteBox ItemsSource="{Binding Path=Data.OperatorTypeNames, Source={StaticResource proxy}}"
ItemTemplate="{StaticResource AutoCompleteBoxItemOperatorTypeTemplate}"
SelectedItem="{Binding OperatorType, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"
ValueMemberPath="OperatorTypeName"
IsTextCompletionEnabled="True"
FilterMode="Contains"
MinimumPrefixLength="3"/>
</Grid>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
The only differences as far as I can see are that:
The Text in "Operator" is using bound to a POCO (Operator) while for "OperatorType" it is bound to a POCO property (OperatorType.OperatorTypeName)
The AutoCompleteBox declarations are slightly different
I've tried numerous settings for the ToolTip DataContext but nothing seems to work.
Question
What do I need to change to get the "OperatorType" customised error styling to work?
Well, it was a bit of a journey, but the solution was to set a DataContext on the TextBlock:
<TextBlock DataContext="{Binding OperatorType}" Text="{Binding OperatorTypeName}">
This causes the Trigger to be pointed at the OperatorType POCO whereas the Text in the box is taken from OperatorType.OperatorTypeName.

DataTrigger with Property = ItemControl.ItemTemplate

I Am having some trouble getting this binding to work. I have several objects within SettingCollection that all have an enum property. I want to generate a control based on what the value of this is. But when I check this value with a data trigger it does not work.
Can anyone provide some insight into how i can accomplish this?
<Window.Resources>
<DataTemplate x:Key="CheckboxNode">
<CheckBox IsChecked="{Binding Status}" Margin="0,5,0,0">
<ContentPresenter Content="{Binding DisplayName}"/>
</CheckBox>
</DataTemplate>
<DataTemplate x:Key="TextboxNode">
<TextBox Text="Badgers"></TextBox>
</DataTemplate>
</Window.Resources>
<ItemsControl ItemsSource="{Binding SettingCollection}">
<ItemsControl.Style>
<Style TargetType="ItemsControl">
<Style.Triggers>
<DataTrigger Binding="{Binding Type}" Value="checkbox">
<Setter Property="ItemsControl.ItemTemplate" Value="{StaticResource CheckboxNode}" />
</DataTrigger>
<DataTrigger Binding="{Binding Type}" Value="textbox">
<Setter Property="ItemsControl.ItemTemplate" Value="{StaticResource TextboxNode}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ItemsControl.Style>
</ItemsControl>
If Type property is in SettingNode class, and SettingCollection is a collection of SettingNode objects, then your binding in the Datatriggers is incorrect. DataTriggers will look for Type property in ItemsControl DataContext (class with SettingCollection). Try to use DataTemplateSelector https://msdn.microsoft.com/en-us/library/system.windows.controls.datatemplateselector(v=vs.110).aspx

WPF radiobuttons IsHitTestVisible not working

I'm using radiobuttons inside a listbox and cannot disable them.
After searching I found links about IsEnabled and IsHitTestVisible. When I set IsEnabled to false the button and text turns grey however it's still clickable. Setting IsHitTestVisible does nothing to change this. My XAMLcode looks like this:
<ListBox ItemsSource="{Binding Source}" BorderThickness="0" VerticalAlignment="Stretch" Background="Transparent" SelectedItem="{Binding SelectedSource, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" >
<ListBox.ItemTemplate>
<DataTemplate>
<RadioButton IsHitTestVisible="{Binding IsEnabled}" IsEnabled="{Binding IsEnabled}" Margin="0 2 0 0" FontSize="12" FontFamily="Segoe UI Regular" Content="{Binding name}" GroupName="GroupList" >
<RadioButton.Style>
<Style TargetType="{x:Type RadioButton}">
<Setter Property="IsChecked" Value="{Binding Path=IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}}}" />
</Style>
</RadioButton.Style>
</RadioButton>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Property in c# that calculates and returns bool.
public bool IsEnabled
{
get
{
IsEnabledCalculate();
return isEnabled;
}
}
Any ideas about how to disable selection?
Using IsHitTestVisible on a RadioButton in ListBox was a good start. This way, when you click the RadioButton, the event goes "through" it and is handled by ListBoxItem (the item gets selected). You can then manipulate IsChecked property by binding it do IsSelected property of the ListBoxItem.
This is however still not enough to achieve waht you want. First, you're binding your IsEnabled property on the wrong level: the RadioButton. As you noticed, this still allows the ListBoxItem to get selected. So, you need to bind your IsEnabled property to the IsEnabled property of ListBoxItm instead:
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsEnabled" Value="{Binding Path=IsEnabled}"/>
</Style>
</ListBox.ItemContainerStyle>
There still is one minor issue here. When your IsEnabled property is changed in the codebehind, the ListBoxItem will get disabled but the RadioButton will still be checked. To prevent this and uncheck the RadioButton whenever the item gets disabled you can use a DataTrigger:
<DataTemplate>
<RadioButton GroupName="GroupList" IsHitTestVisible="False"
Margin="0 2 0 0" FontSize="12" FontFamily="Segoe UI Regular"
Content="{Binding name}" >
<RadioButton.Style>
<Style TargetType="{x:Type RadioButton}">
<Setter Property="IsChecked" Value="{Binding Path=IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}}}" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsEnabled}" Value="False">
<Setter Property="IsChecked" Value="False"/>
</DataTrigger>
</Style.Triggers>
</Style>
</RadioButton.Style>
</RadioButton>
</DataTemplate>

GridViewColumn with ComboBox and UserControl

I have a GridViewColumn with Combobox BAsed on ComboBox selected I want to dynamically put UI elements.Below given is the code.OperatorList has three values "Between","After","Before".Based on this selection the template has to be loaded.If "Between" Multiple TextBox else Single textbox.This part works fine.But to get the content of this and store in Model Class for each row is where i am encountering problem.
<StackPanel>
<ComboBox Grid.Column="0" ItemsSource="{Binding Path=OperatorList}" IsEditable="True"
IsSynchronizedWithCurrentItem="True"
SelectedValue="{Binding ReferenceOperatorSelected}" />
<UserControl x:Name="MyControl">
</UserControl>
</StackPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding ReferenceOperatorSelected}" Value="Between">
<Setter TargetName="MyControl" Property="ContentTemplate" Value="{StaticResource MultipleTextBoxTemplate}"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding ReferenceOperatorSelected}" Value="After">
<Setter TargetName="MyControl" Property="ContentTemplate" Value="{StaticResource SingleTextBoxTemplate}"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding ReferenceOperatorSelected}" Value="Before">
<Setter TargetName="MyControl" Property="ContentTemplate" Value="{StaticResource SingleTextBoxTemplate}"></Setter>
</DataTrigger>
</DataTemplate.Triggers>
<DataTemplate x:Key="MultipleTextBoxTemplate">
<StackPanel>
<TextBox Text="{Binding Path=BetweenValue1,Mode=TwoWay,NotifyOnSourceUpdated=True}" MinWidth="40"></TextBox>
<TextBox Text="{Binding Path=BetweenValue2,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" MinWidth="40"></TextBox>
</StackPanel>
</DataTemplate>
In my Model class I have two properties BetweenValue1 and BetweenVAlue2 ...These are not updated when i key in value in textboxes..
You have not set the Content for your UserControl. just try doing
<UserControl x:Name="MyControl" Content="{Binding}"/>

(WPF) How to change button image background in listBox with buttons in each line ?

i have listbox, and the data template is button :
<ListBox x:Name="lbname" ItemsSource="{Binding myCollection}">
<ListBox.ItemTemplate>
<DataTemplate>
<Button x:Name="btnname" Content="{Binding name}" Click="btnname_Click">
<Button.Background>
<ImageBrush ImageSource="/myApplication;component/images/buttons/normal.png"/>
</Button.Background>
</Button>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
i have two image backgroud for this listBox image (normal.png for normal mode, click.png for selected item in listBox)
The listBox view items in list of buttons, the button image background is normally normal.png
my question is how to change the button image background to click.png for selected one and the old selected button retrieve to normal.png
How to change image background for selected item in listBox with buttons in each line ?
hope this clear, please i spend about one day about this issue
can any one help
Thanks
I haven't tested it, but you need some code that looks like this:
<ListBox x:Name="lbname" ItemsSource="{Binding myCollection}">
<ListBox.ItemTemplate>
<DataTemplate>
<Button x:Name="btnname" Click="btnname_Click">
<Grid>
<Image>
<Image.Style>
<Style>
<Setter Property="Image.Source"
Value="/myApplication;component/images/buttons/normal.png" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected,
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}}"
Value="True">
<Setter Property="Image.Source"
Value="/myApplication;component/images/buttons/click.png" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
<TextBlock Text="{Binding name}" HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Grid>
</Button>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The idea is to bind directly to the IsSelected property of the ListBoxItem object. This is done using a RelativeSource binding. However, I'm guessing that this code doesn't do what you want... I suggest that you might want to use a ToggleButton instead... something like this:
<ListBox x:Name="lbname" ItemsSource="{Binding myCollection}">
<ListBox.ItemTemplate>
<DataTemplate>
<ToggleButton x:Name="btnname" Click="btnname_Click" IsChecked="{Binding
IsSelected, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type
ListBoxItem}}}">
<Grid>
<Image>
<Image.Style>
<Style>
<Setter Property="Image.Source"
Value="/myApplication;component/images/buttons/normal.png" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected,
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}}"
Value="True">
<Setter Property="Image.Source"
Value="/myApplication;component/images/buttons/click.png" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
<TextBlock Text="{Binding name}" HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Grid>
</ToggleButton>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
if you are using MVVM then make a property in viewModel and bind this to ImageBrush as ImageSource,
when you are selecting value in ListView then get selected record and change image path of this property.
Try using Togglebutton instead of button.Use a trigger to check when the IsChecked property of the toggleButton changes. And based on that change your image.

Categories