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?
Related
I wanted to create a combo box column in Data Grid in WPF project. I had a problem to add padding to the cell item (I tried margin instead but it does not highlight the margin when selected). To solve this problem I used following solution to get the demanded effect:
<DataGridTextColumn Header="Saldo"
Binding="{Binding Balance}"
ElementStyle="{StaticResource textBlockColumnElementStyle}"
EditingElementStyle="{StaticResource controlEditingElementStyle}"/>
<DataGridComboBoxColumn Header="Grupa"
DisplayMemberPath="Name"
SelectedValuePath="Id"
SelectedValueBinding="{Binding GroupId}">
<DataGridComboBoxColumn.ElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource"
Value="{Binding Path=DataContext.Groups,
RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" />
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Padding="10"
Text="{Binding Name}"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</DataGridComboBoxColumn.ElementStyle>
<DataGridComboBoxColumn.EditingElementStyle>
<Style TargetType="{x:Type ComboBox}">
<Setter Property="ItemsSource"
Value="{Binding Path=DataContext.Groups,
RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" />
</Style>
</DataGridComboBoxColumn.EditingElementStyle>
</DataGridComboBoxColumn>
Now I wanted to create a style in Resources to provide a parametrized template for another columns in the DataGrid (I want to change for example Font only once). But how can I make the styles to be parametrized in place of usage. For example I ItemsSource or Text property in the inner TextBox?
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 created a combo box in each datagrid row. The following piece of code is used to create the combo box:
<ComboBox Width="166"
ItemTemplate="{StaticResource GridBinding}"
SelectedItem="{Binding Path=Car, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, IsAsync=True}"
SelectedValue="{Binding Path=Car, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, IsAsync=True}">
<ComboBox.GroupStyle>
<GroupStyle HeaderTemplate="{StaticResource GroupHeader}" />
</ComboBox.GroupStyle>
<ComboBox.Style>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding Path=Cars}" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsSelected, RelativeSource={RelativeSource AncestorType=DataGridCell}}" Value="True">
<Setter Property="ItemsSource" Value="{Binding Path=DataContext.GroupedCars, RelativeSource={RelativeSource AncestorType=DataGrid}}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ComboBox.Style>
</ComboBox>
The "Car" property for binding "SelectedItem" in combo box is an object of class "Car" holding some properties like id, name, etc.
The problem I am facing is that when I update the value of "Car" property and call "NotifyPropertyChanged" in its setter, then the value of "SelectedItem" in combo box goes blank/empty.
Please suggest.
The SelectedItem can no longer be found in the Collection (when you update your ItemSource) and gets set to null.
I've simplified your XAML to demonstrate
<ComboBox ItemsSource="{Binding Cars}"
SelectedItem="{Binding Car}">
<ComboBox.Style>
<Style TargetType="ComboBox">
<Style.Triggers>
<Trigger Property="SelectedItem" Value="{x:Null}">
<Setter Property="SelectedIndex" Value="0" />
</Trigger>
</Style.Triggers>
</Style>
</ComboBox.Style>
</ComboBox>
Now the first Item will get selected when you update.
I am attempting to expand a Child Node when its parent is expanded.
Otherwise stated: (Child.IsExpanded == Parent.IsExpanded)
This appears right, but does not seem to work:
<TreeView ItemsSource="{Binding}">
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<Style.Triggers>
<DataTrigger Value="True"
Binding="{Binding Path=IsExpanded,
RelativeSource={RelativeSource
Mode=FindAncestor,
AncestorType={x:Type TreeViewItem},
AncestorLevel=2}}">
<Setter Property="IsExpanded" Value="True" />
</DataTrigger>
</Style.Triggers>
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
Neither does this:
<TreeView ItemsSource="{Binding}">
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<Setter Property="IsExpanded"
Value="{Binding Path=IsExpanded,
RelativeSource={RelativeSource
Mode=FindAncestor,
AncestorType={x:Type TreeViewItem},
AncestorLevel=2}}" />
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
What's missing here?
Thanks in advance.
Both work for me. If you tested it with static TreeViewItems make sure to apply the style via resources, the ItemContainerStyle is only relevant for dynamically created containers. Also note that user-interaction may set a local value, overriding those styles.
I have a ListBox which is populated from a collection of ViewModels, which uses in place editing, which I do by having a couple of styles which I can apply to parts of the DataTemplate which make them visible/collapsed as required. These look something like:
<Style
x:Key="UnselectedVisibleStyle"
TargetType="{x:Type FrameworkElement}">
<Setter
Property="Visibility"
Value="{Binding Path=IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}}, Converter={StaticResource boolToVis}, ConverterParameter=False}" />
</Style>
<Style
x:Key="SelectedVisibleStyle"
TargetType="{x:Type FrameworkElement}">
<Setter
Property="Visibility"
Value="{Binding Path=IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}}, Converter={StaticResource boolToVis}, ConverterParameter=True}" />
</Style>
With my ListBox having it's ItemTemplate given by something like:
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock
Text="{Binding Name}"
Style="{StaticResource UnselectedVisibleStyle}" />
<TextBox
x:Name="textBox"
Text="{Binding Name}"
Style="{StaticResource SelectedVisibleStyle}" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
This works fine, but what I want ideally is to have the TextBox automatically selected when a user clicks the item, ideally in a nice generic way I can use throughout my project, and without too much messing around in my codebehind.
Thanks,
DM.
The following change to your selected Style seemed to work for me:
<Style x:Key="SelectedVisibleStyle" TargetType="{x:Type FrameworkElement}">
<Setter Property="Visibility" Value="{Binding Path=IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}}, Converter={StaticResource boolToVis}, ConverterParameter=True}"/>
<Style.Triggers>
<Trigger Property="Visibility" Value="Visible">
<Setter Property="FocusManager.FocusedElement" Value="{Binding RelativeSource={RelativeSource Self}}"/>
</Trigger>
</Style.Triggers>
</Style>