So I have a Listbox whose items contain an Expander. What I am trying to do is bind the IsExpanded property to the IsSelected property of the parent ListBoxItem. The whole purpose is that if they selected a different listbox item it'll collapse the current selected item and expand the new slected item.
UPDATE (CODE):
<ListBox SelectionMode="Single">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="Padding" Value="0" />
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Boreder BorderThickness="0,0,0,1"
BorderBrush="Black">
<Expander IsExpanded={Binding RelativeSource={RelativeSource AncestorType=ListBoxItem},
Path=IsSelected} />
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The property/binding I was looking for was IsExpanded="{Binding Mode=TwoWay, Path=IsSelected, RelativeSource={RelativeSource AncestorType=ListBoxItem, Mode=FindAncestor}}"
Related
I am trying to create a ComboBox inside a DataGridand to do selectItem binding but when I write this code ,and I select an item in on ComboBox in the column, all the ComboBox items in the DataGrid's column are binding and shows the same selected item. I need to bind each ComboBox item with its selectedItem.
I would be happy to get an help.
this is my code:
<DataGridComboBoxColumn Header="CHOOSE" Width="0.7*"
DisplayMemberPath="Name" SelectedItemBinding="{Binding Path=SelectedReceiver,{RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}">
<DataGridComboBoxColumn.ElementStyle>
<Style TargetType="{x:Type ComboBox}">
<Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}, Path=DataContext.RxList}" />
<Setter Property="ItemTemplate" >
<Setter.Value>
<DataTemplate>
<TextBlock Text="{Binding Path= Name}" Style="{StaticResource GroupBoxHeaderTextBlockStyle}" />
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</DataGridComboBoxColumn.ElementStyle >
<DataGridComboBoxColumn.EditingElementStyle>
<Style TargetType="{x:Type ComboBox}">
<Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}, Path=DataContext.RxList }" />
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{Binding Path= Name}" Style="{StaticResource GroupBoxHeaderTextBlockStyle}"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</DataGridComboBoxColumn.EditingElementStyle>
</DataGridComboBoxColumn>
You bind to DataGrid.ItemsSource.SomeList when you actually need to bind to DataGrid.ItemsSource[x].SomeList.
Basically your list and selected item will always be the same for each column. You can use a static list for your item-model-class (if the list stays the same) and a property for the SelectedItem.
<DataGridComboBoxColumn SelectedItemBinding="{Binding SelectedReceiver}"> <!-- Bind to current item's SelectedReceiver -->
<DataGridComboBoxColumn.ElementStyle>
<Style TargetType="{x:Type ComboBox}">
<Setter Property="ItemsSource" Value="{Binding Path=(modelNamespace:MyModel.RxList)}"/> <!-- Bind to static list property -->
</Style>
</DataGridComboBoxColumn.ElementStyle>
</DataGridComboBoxColumn>
I have a ListBoxItem template with a TextBox element within. When the user clicks the TextBox, I should make the ListBoxItem as the SelectedItem of the ListBox.
<ListBox.ItemTemplate>
<DataTemplate>
<DockPanel Margin="4,0,4,0">
<TextBlock Text="{Binding Path=Value1, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
ToolTip="{Binding Path=Hint, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
VerticalAlignment="Center" />
<TextBox x:Name="TextField"
Margin="2,0,0,0"
Width="{Binding Path=ActWidth, Mode=OneWay}"
Visibility="{Binding Path=VisibleAct, Mode=OneWay}"
/>
</DockPanel>
</DataTemplate>
</ListBox.ItemTemplate>
I have the following Trigger to make the selection:
<ListBox.Resources>
<Style TargetType="ListBoxItem">
<Style.Triggers>
<Trigger Property="IsKeyboardFocusWithin" Value="True">
<Setter Property="IsSelected" Value="True" />
</Trigger>
</Style.Triggers>
</Style>
</ListBox.Resources>
Unfortunately, it works only for
an instant, when I change the focus, the selection disappears.
If I remove the trigger, it works normally but selecting the TextBox does not trigger the selection.
What should I do to make the selection permanent?
Your sample doesn't work because, if the trigger is false, your ListBoxItem is getting the value as it had before triggering. Your ListBoxItem is like 'ehmm, what I was..'.
So you have to set its SelectedValue by adding a default setter that binds its IsSelected state:
<Style TargetType="ListBoxItem">
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode="OneWay", RelativeSource={RelativeSource Self}}" />
<Style.Triggers>
<Trigger Property="IsKeyboardFocusWithin" Value="True">
<Setter Property="IsSelected" Value="True" />
</Trigger>
</Style.Triggers>
</Style>
Setting default setter for IsSelected as OneWay binding to itself will do the job. It will set IsSelected as it was, when the trigger is false.
You could write some code to set the SelectedItem property of the ListBox. You could handle the GotKeyboardFocus event for the TextBox:
<ListBox x:Name="lb2">
<ListBox.ItemTemplate>
<DataTemplate>
<DockPanel Margin="4,0,4,0">
<TextBlock Text="{Binding Path=Value1, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
ToolTip="{Binding Path=Hint, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
VerticalAlignment="Center" />
<TextBox x:Name="TextField"
Margin="2,0,0,0"
Width="{Binding Path=ActWidth, Mode=OneWay}"
Visibility="{Binding Path=VisibleAct, Mode=OneWay}"
GotKeyboardFocus="TextField_GotKeyboardFocus"
/>
</DockPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
private void TextField_GotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
TextBox textBox = sender as TextBox;
lb2.SelectedItem = textBox.DataContext;
}
I rolled my own "splitbutton" that consists of a button, expander and popup with 1-N more buttons. Now the buttons in popup come very thick border around them eventhough button's style has BorderThickness="0". So the border is probably set because buttons are in popup. My question is: How to override border so that all other Button style "properties" are not overridden?
<Popup
IsOpen="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type my:SplitButton}}, Path=IsExpanded}"
PlacementTarget="{Binding ElementName=Button}"
PopupAnimation="Fade"
StaysOpen="False"
>
<Popup.Resources>
<Style TargetType="Border">
<Setter Property="BorderThickness" Value="0" />
</Style>
</Popup.Resources>
<ItemsControl ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type my:SplitButton}}, Path=ItemsSource}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding Converter={ui:ConvertObjectToResource}}" Tag="{Binding}" Click="Control_Click" BorderThickness="0"
Width="{Binding ActualWidth, ElementName=WidthButton}">
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Popup>
EDIT: I can actually do like this:
<Popup.Resources>
<Style TargetType="Button">
<Setter Property="BorderThickness" Value="0" />
</Style>
</Popup.Resources>
This unfortunately overrides button's all other style properties (like padding and background, foreground).
I can also do like this:
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding Converter={ui:ConvertObjectToResource}}" Tag="{Binding}" Click="Control_Click"
Width="{Binding ActualWidth, ElementName=WidthButton}">
<Button.Style>
<Style TargetType="Button">
<Setter Property="BorderThickness" Value="0"></Setter>
<Setter Property="BorderBrush" Value="Transparent"></Setter>
</Style>
</Button.Style>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
but also that overrides button's style. If I try to tackle that by setting BasedOn="ButtonsNormalStyleHere" the borders come back again, i.e. BorderThickness and BorderBrush have no effect.
The "thick black border" is actually background of PopUp which is seen because of button margins -> I am complete idiot.
I have a TreeView that is bound to an ObservableCollection in my ViewModel. I have an issue where if I add an item to the ObservableCollection, sometimes it isn't displayed in the GUI.
I have debugged and found that the item indeed gets added and the CollectionChanged event does indeed get fired on the observable collection. Other parts of my GUI even update to reflect the newly added and selected item. The only problem is that the new item does not show up in the TreeView.
It's a bit strange because sometimes it will show up, sometimes it will flicker up then go away, and sometimes it won't show up at all. Any ideas?
EDIT:
TreeView XAML:
<TreeView Name="cedarTreeView"
ItemsSource="{Binding CurrentFiles}"
ItemTemplate="{StaticResource MyFileTemplate}"
VirtualizingStackPanel.IsVirtualizing="True"
VirtualizingStackPanel.VirtualizationMode="Recycling">
<TreeView.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</TreeView.ItemsPanel>
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
<Setter Property="FontSize" Value="12" />
<Setter Property="AllowDrop" Value="True" />
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
The DataTemplate:
<HierarchicalDataTemplate x:Key="MyFileTemplate"
ItemTemplate="{StaticResource QualifierTemplate}"
ItemsSource="{Binding Qualifiers, Converter={StaticResource SortByNameConverter}}">
<HierarchicalDataTemplate.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
<Setter Property="Visibility" Value="{Binding IsVisible, Converter={StaticResource BoolToVisConverter}}" />
</Style>
</HierarchicalDataTemplate.ItemContainerStyle>
<TextBlock Text="{Binding Name, Mode=OneWay}" ToolTip="{Binding Name, Mode=OneWay}" Tag="{Binding DataContext, RelativeSource={RelativeSource AncestorType=TreeView}}">
<TextBlock.ContextMenu>
Some Context Menu Stuff Here
</TextBlock.ContextMenu>
</TextBlock>
</HierarchicalDataTemplate>
I am adding to the Qualifiers ObservableCollection. It displays them fine when I first open the file and add all of the existing ones. The problem is when i try to create a new one.
Are you perhaps modifying the collection from a separate thread or task?
I have a listbox where the itemtemplate is using a style. The styles specifies a border with a datatrigger setting the visibility of the border to collapsed depending on a property. This works fine except I can still see a very narrow line for each item, in the list, that is collapsed. I was hoping someone could help with how to set the visibility so that there are no visible traces as this is quite apparent when consecutive items have been collapsed.
The datatemplate specifies an outer border with a dockpanel inside of this - there are then stackpanels docked to this.
Any help is appreciated.
Well this is a simplified template:
<DataTemplate x:Key="myTemplate">
<Border BorderThickness="0">
<Border.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsActive}" Value="False">
<Setter Property="Border.Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<DockPanel LastChildFill="True" HorizontalAlignment="Stretch">
<StackPanel DockPanel.Dock="Right" HorizontalAlignment="Right" >
<TextBlock Text="{Binding Path=SeqNo, Converter={StaticResource SeqToTextConv}}"/>
<Label Content="..." />
</StackPanel>
</DockPanel>
</Border>
</DataTemplate>
You are succesfully hiding your item, however, the ListBox wraps each of your items within a ListBoxItem, this adds concepts such as selection to your item. I suspect you are still seeing the ListBoxItem in the case where your items are hidden. You can use the ItemContainerStyle to hide ListBoxItems ...
<ListBox>
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsActive}" Value="False">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
This can also be achieved by populating ListBox.Items only with ListBoxItem instead of other controls:
ListBox.Items.Add(new ListBoxItem {
Content = new CheckBox {Content = "item 1"}
})
or
<ListBox>
<ListBox.Items>
<ListBoxItem>
<CheckBox Content="item 1"/>
</ListBoxItem>
</ListBox.Items>
</ListBox>
Then in the code behind or in the trigger, you can hide the items directly:
ListBox.Items[0].Visibility = Visibility.Collapse
This will hide the item as well as the 4px border. This method gives you control of visibility for each individual item.
I went with ColinE's proposed solution. Here is a full snipped for everybody's convenience. Thanks ColienE.
<ListBox ItemsSource="{Binding Properties}" Height="110">
<ListBox.ItemTemplate>
<HierarchicalDataTemplate>
<CheckBox Content="{Binding Name}" IsChecked="{Binding IsSelected}" Visibility="{Binding Visible}" />
</HierarchicalDataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding Visible}" Value="Collapsed">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>