Binding to the IsSelected property of the parent ListViewItem - wpf

I'm attempting to bind the Visibility property of a TextBlock that's held within the ItemTemplate for a ListView to the IsSelected property of the TextBlock's parent ListViewItem.
With this markup, the TextBlock is always visible.
<ListView x:Name="ItemListView" ItemsSource="{Binding Path=Accounts}" Margin="60,0,0,10" Grid.Row="1" Grid.Column="0">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100">
</ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="200"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Image Width="100" Height="100" Grid.Column="0"></Image>
<StackPanel Grid.Column="1">
<TextBlock Text="{Binding Path=Account.Name}"
FontSize="24" Margin="5,0,0,0" TextWrapping="Wrap" />
</StackPanel>
<TextBlock Grid.Column="3" VerticalAlignment="Bottom"
Visibility="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=IsSelected, Converter={StaticResource boolConverter}, Mode=OneWay}">
Show More Details...
</TextBlock>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Notes:
1. In case it makes any difference, this is WinRT; a Metro app written in C#.
2. boolConverter is a fairly standard converter appears to work correctly.

Use Mode=FindAncestor:
<TextBlock Grid.Column="3" VerticalAlignment="Bottom"
Visibility="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListViewItem}, Path=IsSelected, Converter={StaticResource boolConverter}, Mode=OneWay}">

I think that in this case you will have to use ElementName=ItemListView

#Murven 's answer was close. This is what worked for me:
<TextBlock Visibility="{Binding DataContext.IsSelected, ElementName=ItemListView Converter={StaticResource boolConverter}, Mode=OneWay}">
I had to use DataContext.IsSelected to access the context of the ItemListView.
Not sure if there is a better way.

Related

How to use Binding in trigger, to change another control in WPF?

I have this DataTemplate in style. I have two properties for Image's Source (Image and ImageHover). Now its Image. So I want to change it to ImageHover when the List item from the List Box is hovered by the mouse. How can I make this kind of Binding - Binding in trigger, to change another control's property ?
<DataTemplate x:Key="MetroListBoxItemTemplate">
<Grid Name="grid_menu">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="40"/>
<ColumnDefinition Width="110"/>
</Grid.ColumnDefinitions>
<Image Name="menu_image" Source="{Binding Image}" Stretch="Uniform" Width="40" Height="40" >
</Image>
<StackPanel Grid.Column="1" Margin="5">
<TextBlock Text="{Binding Path=Title, FallbackValue=Title}" FontFamily="Segoe UI Light" FontSize="20"
Foreground="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem, Mode=FindAncestor}, Path=Foreground}" />
</StackPanel>
</Grid>
</DataTemplate>
I use the template here
<ListBox
x:Name="main_menu" HorizontalAlignment="Left" Margin="8,8,0,8" Width="160"
ItemTemplate="{DynamicResource MetroListBoxItemTemplate}"
ItemContainerStyle="{DynamicResource MetroListBoxItemStyle}"
ItemsSource="{Binding Menu}">
</ListBox>

Caliburn Micro with TreeView ContextMenu target does not exist

It seems (from other posts with similar problems) that I am trying to bind the target to an element which doesn't exist in the same visual tree. I have a ContextMenu on the 3rd level in the TreeView, and am trying to set an action to execute a method on the ViewModel via the Tag of the parent element (TextBlock), but can't get it to work.
The XAML is:
<HierarchicalDataTemplate x:Key="FeatureTemplate">
<Grid HorizontalAlignment="Stretch">
<TextBlock Text="{Binding Name}" Tag="{Binding DataContext, RelativeSource={RelativeSource Self}}">
<telerik:RadContextMenu.ContextMenu >
<telerik:RadContextMenu cal:Action.TargetWithoutContext="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Self}}"
cal:Message.Attach="[Event Opened] = [Action ContextMenuOpened($source)]">
<telerik:RadMenuItem Header="Export" cal:Message.Attach="[Event Click]=[Action ContextMenuClick($source)]"/>
</telerik:RadContextMenu>
</telerik:RadContextMenu.ContextMenu>
</TextBlock>
</Grid>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate
x:Key="FormTemplate"
ItemTemplate="{StaticResource FeatureTemplate}"
ItemsSource="{Binding List}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image Source="{Binding Image}" Width="32" Height="32" HorizontalAlignment="Right" Margin="0,3"/>
<TextBlock Grid.Column="1" Text="{Binding Name}" VerticalAlignment="Center" Margin="5"/>
</Grid>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate
x:Key="JobTemplate"
ItemTemplate="{StaticResource FormTemplate}"
ItemsSource="{Binding List}">
<TextBlock Text="{Binding Name}"/>
</HierarchicalDataTemplate>
<telerik:RadTreeView Name="TreeView1"
Grid.Row="2"
cal:Message.Attach="[Event SelectionChanged] = [Action SetSelectedItem($this.SelectedItem)]"
Background="White"
ItemsSource="{Binding AvailableData}"
ItemTemplate="{StaticResource JobTemplate}"
telerik:AnimationManager.IsAnimationEnabled="False" >
</telerik:RadTreeView>
ViewModel code:
public void ContextMenuOpened(FrameworkElement source){}
I get the error that ContextMenuOpened target is not found.
Any help or suggestions would be much appreciated.

Binding to local variable in codebehind

I have to bind to local variable from code behind in ListView.ItemTemplate. I have tried using datacontext:
<ListView Name="listView" ItemsSource="{Binding}" DataContext="{Binding}" VerticalAlignment="Stretch" MaxHeight="300" Background="White" Foreground="Black" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" BorderBrush="#FFCDCDCD" BorderThickness="1" ScrollViewer.VerticalScrollBarVisibility="Auto" IncrementalLoadingTrigger="None" SelectionChanged="listView_SelectionChanged" >
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" MaxHeight="25" >
<TextBlock Grid.Row="0" Grid.Column="0" Text="{Binding Text}" Width="{Binding Width}" />
<Image Grid.Row="0" Grid.Column="1" Source="{Binding Image}" Stretch="None" Width="40" HorizontalAlignment="Left" Margin="4,0,0,0" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
In place of "Width="{Binding Width}"" I want to have property from datacontext - rest of data is connected with itemsSource. How to "tell" xaml to use property from datacontext? (right now it returns error "property not found"). I don't want to change my itemsource and add there width because it is constant for every element (it's obvious ;) ).
Thank you in advance :)
It does use the DataContext, which for the ItemTemplate is the item. You can walk up the tree to find another DataContext, in this case you want the ListView's:
{Binding DataContext.Width,
RelativeSource={RelativeSource AncestorType=ListView}}

textblock in user control TextWrapping not wrapping

I created user control with the textblock. But it will not wrap. This user control servers as a listboxitem.
<Grid x:Name="MainGrid" Height="Auto" Width="Auto">
<StackPanel Orientation="Horizontal">
<Image Height="50" Width="100" Stretch="Uniform" Name="image1" Source="{Binding Path=VideoImageUrl}" Margin="12,12,13,84" MouseLeftButtonDown="image1_MouseLeftButtonDown" MouseEnter="image1_MouseEnter" MouseLeave="image1_MouseLeave" />
<StackPanel Orientation="Vertical" >
<TextBlock TextWrapping="Wrap" Height="Auto" HorizontalAlignment="Left" Name="titleTextBox"
Text="{Binding Path=Title, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}"
VerticalAlignment="Center" Width="Auto" FontSize="14" FontWeight="SemiBold" />
<StackPanel Orientation="Vertical" x:Name="StackPanelDetails">
<TextBlock Height="Auto" HorizontalAlignment="Left" Name="desciptionTextBox"
TextWrapping="Wrap"
Text="{Binding Path=Desciption, Mode=OneWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}"
VerticalAlignment="Center" Width="Auto" />
<Line />
<ItemsControl x:Name="CustomItemsSource" ItemsSource="{Binding Path=LinksList}" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock>
<Hyperlink NavigateUri="{Binding Path=TopicUrl}" RequestNavigate="Hyperlink_RequestNavigate" >
<TextBlock Text="{Binding Path=TopicName}" />
</Hyperlink>
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</StackPanel>
</StackPanel>
</Grid>
A ListBox's default template does not automatically limit the width of its items, but instead uses a ScrollViewer, which shows a horizontal scrollbar when an item is wider than the ListBox.
You can remove the ScrollViewer by replacing the ListBox's Template:
<ListBox ...>
<ListBox.Template>
<ControlTemplate>
<StackPanel IsItemsHost="True"/>
</ControlTemplate>
</ListBox.Template>
...
</ListBox>
Another important thing to note is that a StackPanel in the top-level Grid won't properly resize the contained elements. In the following simplified example the text in the TextBlock is not wrapped because the containing StackPanel simply does not resize it as you expect:
<Grid>
<StackPanel Orientation="Horizontal">
<Image ... />
<Text TextWrapping="Wrap" Text=... />
</StackPanel>
</Grid>
This way it works as you expect:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Image ... />
<TextBlock Grid.Column="1" TextWrapping="Wrap" Text=... />
</Grid>

WPF ListView with column names?

I have this ListView and I'm using a DataTemplate (as you can see) for items.
How can i add column names to the ListView with this ItemTemplate definition?
I cannot use that GridViewColumn definition, because this ListView uses lazy data loading, so when there are too many rows, it fetches them on demand. GridViewColumn somehow does not function with this lazy loading.
<ListView Grid.Row="3">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid x:Name="grid" Background="Transparent" MinWidth="580" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="220" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="70"/>
<ColumnDefinition Width="80"/>
</Grid.ColumnDefinitions>
<TextBlock VerticalAlignment="Center" Grid.Column="0" Text="{Binding Path=Benutzer.Value.Code}"/>
<TextBlock VerticalAlignment="Center" Grid.Column="1" Text="{Binding Path=Nachname}"/>
<TextBlock VerticalAlignment="Center" Grid.Column="2" Text="{Binding Path=Vorname}"/>
<TextBlock VerticalAlignment="Center" Grid.Column="3">
<TextBlock.Text>
<Binding Path="GeburtDate" StringFormat="{}{0:d}"/>
</TextBlock.Text>
</TextBlock>
<Button VerticalAlignment="Center" Grid.Column="4" Style="{StaticResource StyleEditButton}" Content="Öffnen..." Tag="{Binding}" Click="OpenPersonButton_Click"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ListView>
I don't think there is any point in using a ListView if, as you say, you cannot use GridView (or any other view). I would exchange ListView for ItemsControl (or ListBox if you need a selectable item or any of the other things that ListBox offers).
If what you say is true, you could just use a stack panel to position a header row above your data rows:
<StackPanel>
<!-- Header -->
<StackPanel Orientation="Horizontal">
<TextBlock Width="220" TextAlignment="Center" Text="Code" />
<TextBlock Width="100" TextAlignment="Center" Text="Nachname" />
<TextBlock Width="100" TextAlignment="Center" Text="Vorname" />
<TextBlock Width="70" TextAlignment="Center" Text="GeburtDate" />
</StackPanel>
<!-- Data rows -->
<ItemsControl>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" MinWidth="580">
<TextBlock Width="220" TextAlignment="Center" Text="{Binding Path=Benutzer.Value.Code}" />
<TextBlock Width="100" TextAlignment="Center" Text="{Binding Path=Nachname}" />
<TextBlock Width="100" TextAlignment="Center" Text="{Binding Path=Vorname}" />
<TextBlock Width="70" TextAlignment="Center" Text="{Binding Path=GeburtDate, StringFormat={0:d}}" />
<Button VerticalAlignment="Center" Grid.Column="4" Style="{StaticResource StyleEditButton}" Content="Öffnen..." Tag="{Binding}" Click="OpenPersonButton_Click"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
Hope that helps. You might also like to read about virtualizing panels. That might provide the kind of laziness you're talking about.

Resources