I have a View with a Listbox and several textboxes bound to properties of the objects displayed in the listbox. On opening, the listbox is populated with data, and I have the following in the style to ensure than when there are items and nothing is selected, to select the 1st item.
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="SelectedItem" Value="{x:Null}"/>
<Condition Property="HasItems" Value="True"/>
</MultiTrigger.Conditions>
<Setter Property="SelectedIndex" Value="0"/>
</MultiTrigger>
</Style.Triggers>
This works. The first item in the list is always selected when the list gets populated.
Unfortunately, even though the first item is selected, the textboxes that are bound to the selectedItems properties (via their parent grids datacontext) do not seem to receive notification.
Anyone know of a way to force them to update (in XAML if possible). Currently, bindings look thusly:
<TextBox Text="{Binding Weight, ConverterParameter=\{0:F\}, Converter={StaticResource FormattingConverter}, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, ValidatesOnExceptions=True}" />
Edit
Below is the XAML showing the grid PackageDetailsGrid using the PackageList SelectedItem as its datacontext:
<StackPanel Orientation="Vertical" d:LayoutOverrides="Height">
<TextBlock Text="Packages" Style="{DynamicResource TitleText}"/>
<ListBox x:Name="PackageList" Style="{StaticResource SnazzyList}" FocusVisualStyle="{x:Null}" Margin="0" ItemsSource="{Binding Source={StaticResource Packages}}" HorizontalContentAlignment="Stretch" Height="132.5" Background="#18000000">
</ListBox>
<Grid Margin="0,0,8,0">
<Button Content="Add" Margin="20,0,0,0" Width="87" HorizontalAlignment="Left" Style="{DynamicResource ClearButton}" Command="{Binding AddPackageCommand}" Visibility="{Binding ShipmentRecord.TransitStatus, Converter={StaticResource ShippedToVisibilityConverter}}"/>
<Button Content="Delete" Margin="0,0,20,0" Style="{DynamicResource ClearButton}" HorizontalAlignment="Right" Width="87" Height="21.4666666666667" Command="{Binding DeletePackageCommand}" CommandParameter="{Binding SelectedItem, ElementName=PackageList, Mode=Default}" Visibility="{Binding ShipmentRecord.TransitStatus, Converter={StaticResource ShippedToVisibilityConverter}}"/>
</Grid>
</StackPanel>
<Grid x:Name="PackageDetailsGrid" Margin="0" Grid.Column="1" DataContext="{Binding Items.CurrentItem, ElementName=PackageList, Mode=Default}">
<StackPanel Margin="0">
<Grid Margin="0,0,0,8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="40*"/>
<ColumnDefinition Width="60*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="Dimensions" Foreground="White" FontWeight="Bold"/>
<StackPanel Grid.Column="1" Orientation="Horizontal" d:LayoutOverrides="Height">
<TextBox Text="{Binding Height, ConverterParameter=\{0:F\}, Converter={StaticResource FormattingConverter}, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, ValidatesOnExceptions=True}" Width="48" TextWrapping="Wrap" Margin="0" HorizontalAlignment="Left" IsEnabled="{Binding CanEnterPackageDetails}">
<i:Interaction.Behaviors>
<local:SelectAllOnFocusTextboxBehavior/>
</i:Interaction.Behaviors>
</TextBox>
<TextBlock Text="X" Style="{DynamicResource XTextBlockStyle}"/>
<TextBox Text="{Binding Width, ConverterParameter=\{0:F\}, Converter={StaticResource FormattingConverter}, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, ValidatesOnExceptions=True}" Width="48" TextWrapping="Wrap" Margin="0" HorizontalAlignment="Left" IsEnabled="{Binding CanEnterPackageDetails}">
<i:Interaction.Behaviors>
<local:SelectAllOnFocusTextboxBehavior/>
</i:Interaction.Behaviors>
</TextBox>
<TextBlock Text="X" Style="{DynamicResource XTextBlockStyle}"/>
<TextBox Text="{Binding Length, ConverterParameter=\{0:F\}, Converter={StaticResource FormattingConverter}, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, ValidatesOnExceptions=True}" Width="48" TextWrapping="Wrap" Margin="0" HorizontalAlignment="Left" IsEnabled="{Binding CanEnterPackageDetails}">
<i:Interaction.Behaviors>
<local:SelectAllOnFocusTextboxBehavior/>
</i:Interaction.Behaviors>
</TextBox>
</StackPanel>
</Grid>
</StackPanel>
</Grid>
Here is some xaml for a TextBox whose Text property is bound to the SelectedItem property of the list view. It includes your code for automatically selecting the first item when there is nothing selected.
Is this the kind of solution you're looking for? If not, I need more info i.e. all of the relevant code you're working on.
<StackPanel>
<TextBox Text="{Binding SelectedItem, ElementName=MyListView}" />
<ListView x:Name="MyListView">
<ListView.Style>
<Style TargetType="ListView">
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="SelectedItem" Value="{x:Null}"/>
<Condition Property="HasItems" Value="True"/>
</MultiTrigger.Conditions>
<Setter Property="SelectedIndex" Value="0"/>
</MultiTrigger>
</Style.Triggers>
</Style>
</ListView.Style>
<ListView.Items>
<System:String>hello</System:String>
<System:String>world</System:String>
</ListView.Items>
</ListView>
</StackPanel>
Related
In my example, I have a list box (CommentsList). Every item in the list has another inner list ( repliesList). When I have have some commens the vertical scroll bar is shown but when I have a comment with a list or replays the Vertical Scroll bar is not shown.
Here you have the xaml design, could you please tell me where is the error?
CommentsPanel.xaml:
<DockPanel LastChildFill="True" HorizontalAlignment="Stretch" VerticalAlignment="Top">
<TextBlock DockPanel.Dock="Bottom" TextWrapping="Wrap" Visibility="{Binding HasComments, Converter={StaticResource reversedBooleanToVisibilityConverter}}" Text="There are no comments on this row." x:Name="NoCommentsLabel"/>
<TextBlock DockPanel.Dock="Bottom" TextWrapping="Wrap" Text="Use Previous and Next to navigate throught all comments." x:Name="NoCommentsOpenDiagramsLabel">
<TextBlock.Visibility>
<MultiBinding Converter="{StaticResource multiBooleanToVisibilityConverter}">
<Binding Path="HasComments"/>
<Binding Path="CommentsOnOpenDiagrams" />
</MultiBinding>
</TextBlock.Visibility>
</TextBlock>
<ListBox DockPanel.Dock="Bottom" x:Name="CommentsList" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ItemsSource="{Binding Path=CommentsListItems.View}"
HorizontalContentAlignment="Stretch" BorderThickness="0" Background="Transparent" SelectionMode="Single" SelectionChanged="CommentsList_OnSelectionChanged"
Width="{Binding Width, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}, AncestorLevel=1}}">
<ListBox.ItemTemplate>
<DataTemplate>
<wpfControlLibrary:CommentThread Margin="2,2,5,5" IsSelected="{Binding Path=IsSelected, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type ListBoxItem}}, UpdateSourceTrigger=PropertyChanged}"
Width="{Binding Width, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}, AncestorLevel=1}}">
</wpfControlLibrary:CommentThread>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DockPanel>
wpfControlLibrary:CommentThread :
<Border x:Name="borderMain" BorderBrush="Transparent" BorderThickness="1" Background="#00000000" Padding="3">
<Grid x:Name="commentGrid">
<Grid x:Name="threadGrid" Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*"/>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ContentPresenter Grid.Row="0" Grid.Column="0" Content="{Binding Path=CommentModel}">
<ContentPresenter.Style>
<Style TargetType="ContentPresenter">
<Setter Property="ContentTemplate" Value="{StaticResource NoLyncTemplate}" />
</Style>
</ContentPresenter.Style>
</ContentPresenter>
**<ListBox Margin="50, 0, 0 0" Grid.Row="1" x:Name="repliesList" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ItemContainerStyle="{StaticResource ContainerStyle}" HorizontalContentAlignment="Stretch" SelectionChanged="RepliesList_OnSelectionChanged" BorderThickness="0" Background="Transparent" SelectionMode="Single" Grid.Column="0" Grid.ColumnSpan="2" Width="{Binding Width, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}, AncestorLevel=1}}" ItemsSource="{Binding Path=CommentRepliesListItems.View}"**
>
<Grid Grid.Row="3" Margin="50,0,0,0" >
<TextBlock x:Name="watermark_TextBlock" Text="Reply..." Foreground="{StaticResource brushWatermarkForeground}" Background="{StaticResource brushWatermarkBackground}"
Width="{Binding ActualWidth, ElementName=threadGrid, Mode=OneWay}" HorizontalAlignment="Left" MouseLeftButtonUp="Watermark_OnMouseLeftButtonUp" KeyUp="Watermark_KeyUp">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="True"></Condition>
<Condition Property="Visibility" Value="Visible"></Condition>
</MultiTrigger.Conditions>
<Setter Property="Cursor" Value="IBeam"></Setter>
</MultiTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
<TextBox x:Name="replyBox" Text="" Visibility="Collapsed" HorizontalAlignment="Stretch" TextWrapping="Wrap" VerticalAlignment="Top" Height="40"
VerticalScrollBarVisibility="Auto" LostFocus="CommentEdit_OnLostFocus"
KeyUp="ReplyBox_OnKeyUp"
/>
</Grid>
</Grid>
</Grid>
</Border>
The solution is use physical scrolling instead of logical scrolling in the listbox:
ScrollViewer.CanContentScroll="False"
I have an hierarchical Treeview which each item contains a complexed entity which consists of:
Border
-- Check box
-- TextBlock
i want to change the opacity of the border whenever the checkbox IsEnabled property is set to "False"
this is what i have:
<HierarchicalDataTemplate DataType="{x:Type sd:LegendTreeViewItem}" ItemsSource="{Binding Path=SubSensors}">
<Border x:Name="treeViewItemBorder" Height="24" Margin="3 3 3 3" Width="350" Background="{Binding Path=Color}" CornerRadius="8 8 8 8">
<StackPanel Orientation="Horizontal">
<CheckBox x:Name="treeViewItemCheckbox" Margin="5 5 5 5" Click="CheckBox_Click" IsChecked="{Binding IsChecked}" VerticalAlignment="Center" IsEnabled="{Binding Enabled}" Style="{StaticResource OpacityOnDisabled}"/>
<TextBlock Height="Auto" FontFamily="Tahoma" FontWeight="Bold" Foreground="Black" HorizontalAlignment="Left" Text="{Binding Path=Name}"
VerticalAlignment="Center" ToolTip="{Binding Path=Name}"/>
</StackPanel> </Border>
</HierarchicalDataTemplate>
<TreeView x:Name="legendTypeTree" Grid.Row="1" Foreground="White" ItemsSource="{Binding ElementName=uc, Path=TypeItemsSource}">
<TreeView.Resources>
<Style x:Key="OpacityOnDisabled" TargetType="{Binding RelativeSource={RelativeSource AncestorType=Border}}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsEnabled}" Value="False">
<Setter Property="Border.Opacity" Value="0.3"/>
<Setter Property="Border.Background" Value="White"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TreeView.Resources>
</TreeView>
Move both HierarchicalDataTemplate and Style for the Border in the TreeView resources. (Style first in order for the StaticResource OpacityOnDisabled to resolve properly).
You want to change the style of the border, so there is no sense to apply style on the checkbox. Move Style="{StaticResource OpacityOnDisabled}" from the CheckBox to the Border element. Set the correct type of the style and for the DataTrigger change the bindinig to Binding="{Binding ElementName=treeViewItemCheckbox, Path=IsChecked}"
In the end you should have something like, which should do what you want:
Result:
<TreeView
x:Name="legendTypeTree"
Grid.Row="1"
Foreground="White"
ItemsSource="{Binding ElementName=uc, Path=TypeItemsSource}">
<TreeView.Resources>
<Style x:Key="OpacityOnDisabled" TargetType="{x:Type Border}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=treeViewItemCheckbox, Path=IsChecked}" Value="False">
<Setter Property="Border.Opacity" Value="0.3"/>
<Setter Property="Border.Background" Value="White"/>
</DataTrigger>
</Style.Triggers>
</Style>
<HierarchicalDataTemplate DataType="{x:Type sd:LegendTreeViewItem}" ItemsSource="{Binding Path=SubSensors}">
<Border
x:Name="treeViewItemBorder"
Height="24"
Margin="3 3 3 3"
Width="350"
Background="{Binding Path=Color}"
CornerRadius="8 8 8 8"
Style="{StaticResource OpacityOnDisabled}">
<StackPanel Orientation="Horizontal">
<CheckBox
x:Name="treeViewItemCheckbox"
Margin="5 5 5 5"
Click="CheckBox_Click"
IsChecked="{Binding IsChecked}"
VerticalAlignment="Center"
IsEnabled="{Binding Enabled}" />
<TextBlock
Height="Auto"
FontFamily="Tahoma"
FontWeight="Bold"
Foreground="Black"
HorizontalAlignment="Left"
Text="{Binding Path=Name}"
VerticalAlignment="Center"
ToolTip="{Binding Path=Name}"/>
</StackPanel>
</Border>
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
I have a data grid built using DataGridTemplateColumns. When a validation error exists, we are displaying it on the Textblock of the CellTemplate. When scrolling occurs, the error styling is lost after it scrolls off the page.
In my control resources:
<ControlTemplate x:Key="validationTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Foreground="Yellow"
FontSize="20"
VerticalAlignment="Center"
Margin="0,0,2,2">!</TextBlock>
<Border Grid.Column="1"
BorderBrush="Yellow"
BorderThickness="1"
Margin="0"
Padding="0"
Height="19">
<AdornedElementPlaceholder/>
</Border>
</Grid>
</ControlTemplate>
<Style x:Key="TextBlockValidationStyle" TargetType="{x:Type TextBlock}">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={RelativeSource Self},
Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
And Within the DataGrid:
<DataGridTemplateColumn Header="Destination Column">
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox IsEditable="True"
IsTextSearchCaseSensitive="{Binding ElementName=caseSensitiveSearch, Path=IsChecked}"
ItemsSource="{Binding AllSuggestedNames}"
TextSearch.TextPath="SuggestedName"
Text="{Binding ColumnMapping.DestinationColumnName, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Style="{StaticResource TextBlockValidationStyle}"
Text="{Binding ColumnMapping.DestinationColumnName,
ValidatesOnDataErrors=True,
NotifyOnValidationError=True,
UpdateSourceTrigger=PropertyChanged}"
Validation.ErrorTemplate="{StaticResource validationTemplate}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Solved it! Wrapping each CellTemplate's interior of their DataTemplate with an AdornerDecorator fixed it right up!
<DataTemplate>
<AdornerDecorator>
<TextBlock Style="{StaticResource TextBlockValidationStyle}"
Text="{Binding ColumnMapping.DestinationColumnName,
ValidatesOnDataErrors=True,
NotifyOnValidationError=True,
UpdateSourceTrigger=PropertyChanged}"
Validation.ErrorTemplate="{StaticResource validationTemplate}"/>
</AdornerDecorator>
</DataTemplate>
Is it possible to use templates within templates?
For instance, I have the following two templates:
<HierarchicalDataTemplate
x:Key="RecursiveTemplate"
ItemsSource="{Binding Children}">
<StackPanel Margin="1" Orientation="Horizontal">
<Ellipse Fill="DarkGreen" Width="14" Height="14"/>
<TextBlock
MouseDown="OnTreeMouseDown"
TargetUpdated="OnTargetUpdated"
Visibility="{Binding Editing, Converter={StaticResource visibilityInverter}}"
Margin="5"
Text="{Binding Name}"/>
<TextBox
PreviewKeyDown="OnTreeKeyDown"
Visibility="{Binding Editing, Converter={StaticResource visibilityConverter}}"
Margin="2"
Text="{Binding Name}"/>
</StackPanel>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate
x:Key="ContainerTemplate"
ItemsSource="{Binding Children}">
<StackPanel Margin="1" Orientation="Horizontal">
<Ellipse Fill="DarkBlue" Width="14" Height="14"/>
<TextBlock
MouseDown="OnTreeMouseDown"
TargetUpdated="OnTargetUpdated"
Visibility="{Binding Editing, Converter={StaticResource visibilityInverter}}"
Margin="5"
Text="{Binding Name}"/>
<TextBox
PreviewKeyDown="OnTreeKeyDown"
Visibility="{Binding Editing, Converter={StaticResource visibilityConverter}}"
Margin="2"
Text="{Binding Name}"/>
</StackPanel>
</HierarchicalDataTemplate>
There's a section of identical XAML:
<TextBlock
MouseDown="OnTreeMouseDown"
TargetUpdated="OnTargetUpdated"
Visibility="{Binding Editing, Converter={StaticResource visibilityInverter}}"
Margin="5"
Text="{Binding Name}"/>
<TextBox
PreviewKeyDown="OnTreeKeyDown"
Visibility="{Binding Editing, Converter={StaticResource visibilityConverter}}"
Margin="2"
Text="{Binding Name}"/>
Is it possible to move that to a resource and refer to it by name, rather than repeat it?
The answer appears to be "almost"
<Style x:Key="textBlockStyle" TargetType="TextBlock">
<Setter Property="Visibility" Value="{Binding Editing, Converter={StaticResource visibilityInverter}}"/>
<Setter Property="Margin" Value="4"/>
<Setter Property="Text" Value="{Binding Name}"/>
<EventSetter Event="MouseDown" Handler="OnTreeMouseDown"/>
</Style>
<Style x:Key="textBoxStyle" TargetType="TextBox">
<Setter Property="Visibility" Value="{Binding Editing, Converter={StaticResource visibilityConverter}}"/>
<Setter Property="Margin" Value="1"/>
<Setter Property="Text" Value="{Binding Name, NotifyOnSourceUpdated=True}"/>
<EventSetter Event="PreviewKeyDown" Handler="OnTreeKeyDown"/>
</Style>
Then the templates reduce to
<HierarchicalDataTemplate
x:Key="RecursiveTemplate"
ItemsSource="{Binding Children}">
<StackPanel Margin="1" Orientation="Horizontal">
<Ellipse Fill="DarkGreen" Width="14" Height="14"/>
<TextBlock
Style="{StaticResource textBlockStyle}"/>
<TextBox
SourceUpdated="OnSourceUpdated"
Style="{StaticResource textBoxStyle}"/>
</StackPanel>
</HierarchicalDataTemplate>
However, note you cannot put SourceUpdated in a style, as it's not covered by EventSetter
I still didn't get it. Could you please show me exactly how to override ListBox's default behavior.
Everytime when ListBoxItem is selected the Border's background should be changed. Not the background of the whole row but only background of the border which's specified.
<ListBox ItemsSource="{Binding Source={StaticResource AssetsViewSource}}">
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderThickness="2" BorderBrush="Black">
<StackPanel>
<TextBlock Text="Name: " />
<TextBlock Text="{Binding Name}" />
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Use the DataTemplate's Triggers collection, with a RelativeSource to get you to the containing ListBoxItem:
<DataTemplate>
<Border BorderThickness="2" BorderBrush="Black" Name="Bd">
<StackPanel>
<TextBlock Text="Name: " />
<TextBlock Text="{Binding Name}" />
</StackPanel>
</Border>
<DataTemplate.Triggers>
<DataTrigger Value="True"
Binding="{Binding
IsSelected,
RelativeSource={RelativeSource
AncestorType={x:Type ListBoxItem}}}">
<!-- everybody loves HotPink -->
<Setter TargetName="Bd" Property="Background" Value="HotPink"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
Simply add the following into the ListBox Item tag
<ListBox.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent" />
</ListBox.Resources>
That should do the trick..