C# XAML Master Detail Binding does not work - c#

I want to display a List in a ListView with Master Detail View. The Master View works fine, but the binding to the detail view is not working. What am i doing wrong?
Code Behind:
DataContext = new VirtualizingCollection<LinesSummary>(fs, 100)
LinesSummary Class:
public class LinesSummary {
public string dateString { get; set; }
}
XAML:
<StackPanel>
<ListView Margin="5" Style="{DynamicResource lvStyle}" Height="200" x:Name="Master"/>
<ListView Margin="5" Style="{DynamicResource lvStyle_Detail}" Height="200" x:Name="Detail"/>
</StackPanel>
Dynamic Resource for Master View:
<Setter Property="VirtualizingStackPanel.IsVirtualizing" Value="True"/>
<Setter Property="VirtualizingStackPanel.VirtualizationMode" Value="Recycling"/>
<Setter Property="ScrollViewer.IsDeferredScrollingEnabled" Value="True"/>
<Setter Property="ListView.ItemsSource" Value="{Binding}"/>
<Setter Property="ListView.View">
<Setter.Value>
<GridView>
<GridViewColumn Header="Date" Width="100">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding dateString}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</Setter.Value>
</Setter>
</Style>
Dynamic Resource for Detail View:
<Style x:Key="lvStyle_Detail" TargetType="{x:Type ListView}">
<Setter Property="VirtualizingStackPanel.IsVirtualizing" Value="True"/>
<Setter Property="VirtualizingStackPanel.VirtualizationMode" Value="Recycling"/>
<Setter Property="ScrollViewer.IsDeferredScrollingEnabled" Value="True"/>
<Setter Property="ListView.ItemsSource" Value="{Binding ElementName=Master, Path=SelectedItem.LinesSummary}"/>
<Setter Property="ListView.View">
<Setter.Value>
<GridView>
<GridViewColumn Header="aaa" Width="100">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding dateString}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</Setter.Value>
</Setter>
</Style>

The ItemsSource of a ListView can only be bound to an IEnumerable so even if you bind the ItemsSource property of the second ListView like this it won't work:
ItemsSource="{Binding ElementName=Master, Path=SelectedItem}"
...because LinesSummary is not an IEnumerable.
Since there is only a maximum of one item selected in Master, you might as well bind a TextBlock to the dateString property of its SelectedItem:
<StackPanel>
<ListView Margin="5" Style="{DynamicResource lvStyle}" Height="200" x:Name="Master"/>
<ListView Margin="5" Style="{DynamicResource lvStyle_Detail}" Height="200" x:Name="Detail">
<ListViewItem>
<TextBlock Text="{Binding Path=SelectedItem.dateString, ElementName=Master}" />
</ListViewItem>
</ListView>
</StackPanel>
Remove this setter from the lvStyle_Detail:
<Setter Property="ListView.ItemsSource" Value="{Binding ElementName=Master, Path=SelectedItem.LinesSummary}"/>

Related

WPF bind property of current ListView row

I am trying to implement a TreeView inside my ListView.
I would like the backgroud of my TreeBox would be the same as its "Father" row.
I guess there is a possibility to bind its BackGround property to its row's BackGround property, but how to do that?
Here is an image to explain the issue :
1st line is selected
2nd line is Over
I also put my XAML, in case that would help :
<ListView x:Name="ListView4" SelectedItem="{Binding SelectedRepere}" ItemsSource="{Binding ListeDesReperes}" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="4" MouseDoubleClick="ListView_MouseDoubleClick" GridViewColumnHeader.Click="GridViewColumnHeaderClickedHandler" ContextMenuOpening="ListView4_ContextMenuOpening" SelectionChanged="ListView4_SelectionChanged" Visibility="{Binding Grid4Visible, Converter={StaticResource BoolToVisConverter}}" >
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsUniqueGeometry}" Value="true">
<Setter Property="FontWeight" Value="Bold" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
<ListView.ContextMenu>
<ContextMenu x:Name="Context4">
<MenuItem x:Name="Context4MakeLonger" Header="{x:Static p:Resources.MakeLonger}" Click="Make_Longer"/>
<MenuItem x:Name="Context4Distinguer" Header="{x:Static p:Resources.DistributeToAss}" Click="DistinguerDetailRepere"/>
<MenuItem x:Name="Context4Search" Header="{x:Static p:Resources.Search}" Click="Search_Detail"/>
</ContextMenu>
</ListView.ContextMenu>
<ListView.View>
<GridView AllowsColumnReorder="true" x:Name="GridView4">
<GridViewColumn DisplayMemberBinding="{Binding Path=ID}" Header="ID" Width="200"/>
<GridViewColumn Header="Name">
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<TreeView BorderThickness="0" x:Name="treeviewList" ItemsSource="{Binding RepereTree}" Width="Auto">
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
</Style>
</TreeView.ItemContainerStyle>
<TreeView.ItemTemplate>
<DataTemplate>
<TreeViewItem ItemsSource="{Binding ListeSubReperes}">
<TreeViewItem.Header>
<Grid>
<TextBlock Foreground="#FF042271" Text="{Binding NameOri}" HorizontalAlignment="Left" VerticalAlignment="Center" Grid.Column="0" Tag="{Binding Name}" MouseMove="mouseOverNameRepere" ToolTip="{Binding Path=ToolTipModifications}" MouseDown="TreeView_Main_Click"/>
</Grid>
</TreeViewItem.Header>
<TreeViewItem.ItemTemplate>
<DataTemplate>
<Grid Margin="-20,0,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Foreground="#FF042271" Text="{Binding Name}" Tag="{Binding IdRepereOri}" Margin="10,0,0,0" HorizontalAlignment="Left" VerticalAlignment="Center" Grid.Column="0"MouseDown="TreeView_Sub_Click"/>
</Grid>
</DataTemplate>
</TreeViewItem.ItemTemplate>
</TreeViewItem>
</DataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
...
Edit :
Finally, putting "transparent doesn't completely solve the proble, sometimes it works, but sometimes when selecting the Treeview, it seems it gets selected, and I have the following result :
Then when I unselect it, it gives that result :
I would like the Treeview would be as any element of my row, for this the only way I found is add on each TextBlock a MouseDown event, then I do this :
private void TreeView_Main_Click(object sender, MouseButtonEventArgs e)
{
TextBlock item = (TextBlock)sender;
string name = (string)item.Text;
Repere rep = contexte.ListeDesReperes.FirstOrDefault(x => x.Name == name);
if (rep != null)
{
contexte.SelectedRepere = rep;
}
}
private void TreeView_Sub_Click(object sender, MouseButtonEventArgs e)
{
TextBlock item = (TextBlock)sender;
long idOri = (long)item.Tag;
Repere rep = contexte.ListeDesReperes.FirstOrDefault(x => x.ID==idOri);
if (rep != null)
{
contexte.SelectedRepere = rep;
}
}
Don't know if there is an easier way to do that, but that's all what I found until now.
Try to set the Background property of the TreeView to Transparent:
<TreeView Background="Transparent">
I put it here for who would come here :
how to change highlight values
Here it is well explained what are SystemColors parameters, on the end just had to add :
<TreeView.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent" />
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey }" Color="Transparent" />
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Transparent" />
</TreeView.Resources>

Style not taken in account on GridViewColumn ToolTip

So I have the following problem :
In my ListView, I want to add ToolTips to specific GridViewColumns.
Sometimes these ToolTips are empty, and I need to hide them.
When I have a ToolTip on a ListView Line, I encounter no problem doing the following in my App.xaml file:
<Style TargetType="ToolTip">
<Style.Triggers>
<Trigger Property="Content" Value="{x:Static sys:String.Empty}">
<Setter Property="Visibility" Value="Collapsed" />
</Trigger>
<Trigger Property="Content" Value="{x:Null}">
<Setter Property="Visibility" Value="Collapsed" />
</Trigger>
</Style.Triggers>
</Style>
But in the case a ToolTip is applied to only one column of my ListView, my XAML is the following :
<GridViewColumn Header="{x:Static p:Resources.Name}" Width="100">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Path=Name}" Tag="{Binding Name}"
MouseMove="mouseOverNameRepere">
<TextBlock.ToolTip>
<StackPanel>
<Grid>
<TextBlock Grid.Column="0"
Text="{Binding Path=ToolTipModifications}"
TextAlignment="Left" HorizontalAlignment="Left"/>
</Grid>
</StackPanel>
</TextBlock.ToolTip>
</TextBlock>
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
How can I hide the ToolTip when it is empty? The code in my App.xaml is not working.
Also tried to do it in code behind :
TextBlock item = (TextBlock)sender;
ToolTip toolTip = (ToolTip)item.ToolTip;
But second line gives me an exception as item.ToolTip is a StackPanel object and cannot be converted?
In fact I calculate the ToolTip content only when I enter the TextBox element, so I thought I would then check and apply toolTip.Visibility at this moment, but I couldn't.
Your Style should work if you set the ToolTip property of the TextBlock like this:
<TextBlock Text="{Binding Path=Name}" Tag="{Binding Name}" MouseMove="mouseOverNameRepere"
ToolTip="{Binding Path=ToolTipModifications}" />
Use Rectangle instead of Tooltip
<GridViewColumn Header="{x:Static p:Resources.Name}" Width="100">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Path=Name}" Tag="{Binding Name}"/>
<Rectangle Fill="Transparent" ToolTipService.ToolTip="{Binding Path=ToolTipModifications}" MouseEnter="UIElement_OnMouseEnter"/>
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
Then check if ToolTipModifications is empty in MouseEnter event
private void UIElement_OnMouseEnter(object sender, MouseEventArgs e)
{
if (sender is Rectangle rectangle)
{
if (string.IsNullOrEmpty(rectangle.ToolTip.ToString()))
{
rectangle.Visibility = Visibility.Collapsed;
}
}
}
Please try this code:
<DataGridTextColumn Width="200" Binding="{Binding Name}">
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource TextBlockDefaultStyle}">
<Setter Property="ToolTip" Value="{Binding Name}">
<Setter Property="ToolTipService.ShowDuration" Value="6000">
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>

Selecting item in a virtualized XAML ListView throws an StackOverflow

I have this XAML form with a virtualized ListView to show a grid:
<Window x:Class="WpfVirtualList.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Style x:Key="lvStyle" TargetType="{x:Type ListView}">
<Setter Property="VirtualizingStackPanel.IsVirtualizing" Value="True"/>
<Setter Property="VirtualizingStackPanel.VirtualizationMode" Value="Recycling"/>
<Setter Property="ScrollViewer.IsDeferredScrollingEnabled" Value="True"/>
<Setter Property="ListView.ItemsSource" Value="{Binding}"/>
<Setter Property="ListView.View">
<Setter.Value>
<GridView>
<GridViewColumn Header="Cups" Width="200">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding CUPS}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="MeterId" Width="150">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding MeterID}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Matricula" Width="100">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding MatriculaCT}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding IsLoading}" Value="True">
<Setter Property="ListView.Cursor" Value="Wait"/>
<Setter Property="ListView.Background" Value="LightGray"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<ListView x:Name="lv" HorizontalContentAlignment="Stretch" Style="{DynamicResource lvStyle}" SelectionChanged="lv_SelectionChanged" />
</Grid>
</Window>
And when I select an item everything works OK...
But when I select a second item the system throws an StackOverflow... and I don't know why.
I have breakpoints in all the virtual list methods, but no one of them are called when I click on the second item.
I have a breakpoint in SelectionChanged event, and isn't called either.
//CUPS is the id
private void lv_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if(e.RemovedItems.Count > 0)
Debug.WriteLine("selected: "+((ItemClass)e.RemovedItems[0]).CUPS);
if(e.AddedItems.Count > 0)
Debug.WriteLine("unselected: " + ((ItemClass)e.AddedItems[0]).CUPS);
}
I fixed it controlling the GotFocus event and unselecting all... but this is not the way to solve this.
private void lv_GotFocus(object sender, RoutedEventArgs e)
{
lv.UnselectAll();
}

Progressbar in ListBox Background?

I have the following Listbox:
<ListBox Margin="5" Grid.Column="0" Name="ListboxSelectUpdate">
<ListBox.ItemTemplate>
<DataTemplate>
<ProgressBar Visibility="Visible">
<ProgressBar.Style>
<Style TargetType="{x:Type ProgressBar}">
<Style.Triggers>
<DataTrigger Binding="{Binding Progress}" Value="0">
<Setter Property="Visibility" Value="Hidden"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ProgressBar.Style>
<ProgressBar.Template>
<ControlTemplate>
<AdornedElementPlaceholder Name="adorner">
<Grid>
<TextBlock Width="70" FontStyle="Italic" FontWeight="Bold">Version:</TextBlock>
<TextBlock FontWeight="Bold" Text="{Binding Path=Version}"></TextBlock>
</Grid>
</AdornedElementPlaceholder>
</ControlTemplate>
</ProgressBar.Template>
</ProgressBar>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
In this Listbox I want to show different available Updates / Versions for a program.
Now I want to have a Progressbar in the Background of the ItemTemplate, which is only visible if the Progess-Property (int) is not zero. (so if the Update starts, the Progress-Property isnt zero and the Progressbar should be visible).
My Problem: I cant see anything, no Progressbar and no TexbBlocks.
Where is my misstake?
Your template is a bit wrong. You have misused AdornedElementPlaceholder element which, according to MSDN should be used only for validation templates. And you don't put things inside AdornedElementPlaceholder, it's a place where decorated control is put. If you want to stack controls on top of each other then use Grid. Try this ListBox template instead:
<ListBox Margin="5" ItemsSource="{Binding Path=MyList}">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<ProgressBar Minimum="0" Maximum="100" Value="{Binding Progress, Mode=OneWay}">
<ProgressBar.Style>
<Style TargetType="{x:Type ProgressBar}">
<Style.Triggers>
<DataTrigger Binding="{Binding Progress}" Value="0">
<Setter Property="Visibility" Value="Hidden"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ProgressBar.Style>
</ProgressBar>
<StackPanel Orientation="Horizontal">
<TextBlock Width="70" FontStyle="Italic" FontWeight="Bold">Version:</TextBlock>
<TextBlock FontWeight="Bold" Text="{Binding Path=Version}"/>
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

Binding a command to viewModel inside a Context menu sitting inside a ListView

I am trying to bind a context menu item to a command that I have defined in my ViewModel. The context menu sits inside a ListView that I also have bound to a CollectionViewSource, and this I think is the cause of the problem.
I have managed to bind the selected item in the listView collection to my ViewModel, but when I am trying to use the same way to bind the context menu item command to my ViewModel it doesn't work. I hope that anybody have the time to read through all the code below and give me some idea about what I am doing wrong.
Ps. I have had to change some of the names in order to not give away what the application is about.
In my ViewModel I have defined the followning:
public ObservableCollection<ListItemViewModel> ListViewItemViewModels {get; set;}
public MyListItem SelectedListItemViewModel {get; set;}
private RelayCommand _runCommand;
public ICommand RunCommand {
get {
return _runCommand ??
( _runCommand = new RelayCommand( param => RunReport(), param => CanRunReport ) );
}
}
private void RunReport() {
Logger.Debug("Run report");
}
Then in my View I have set upp a ListView as follows:
<ListView DataContext="{StaticResource ListGroups}"
ItemsSource="{Binding}"
ItemContainerStyle="{StaticResource ListItemStyle}"
IsSynchronizedWithCurrentItem="True"
SelectedItem="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Grid},AncestorLevel=1 }, Path=DataContext.SelectedListItem, UpdateSourceTrigger=PropertyChanged}"
Margin="10,10,0,10">
<ListView.GroupStyle>
<StaticResourceExtension ResourceKey="AccountGroupStyle"/>
</ListView.GroupStyle>
<ListView.View>
<GridView>
<GridViewColumn Header="Title" DisplayMemberBinding="{Binding Path=DisplayTitle}"/>
<GridViewColumn Header="Date" DisplayMemberBinding="{Binding Path=DateString}"/>
</GridView>
</ListView.View>
<ListView.ContextMenu>
<ContextMenu Name="ListViewContextMenu">
<MenuItem Header="Run" Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Grid},AncestorLevel=1 }, Path=DataContext.RunCommand}"/>
</ContextMenu>
</ListView.ContextMenu>
</ListView>
The CollectionViewSource is defined as follows:
<DataTemplate x:Key="ListViewListTemplate" DataType="{x:Type ViewModels:ListItemViewModel}">
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Path=DisplayTitle}" Margin="8,0,0,0"/>
</StackPanel>
</DataTemplate>
<CollectionViewSource Source="{Binding Path=ListItemViewModels}" x:Key="ListItemGroups">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="ListItemGroupName"/>
</CollectionViewSource.GroupDescriptions>
<CollectionViewSource.SortDescriptions>
<ComponentModel:SortDescription PropertyName="Index" Direction="Ascending"/>
<ComponentModel:SortDescription PropertyName="DisplayTitle" Direction="Ascending"/>
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
<GroupStyle x:Key="ListItemGroupStyle">
<GroupStyle.HeaderTemplate>
<DataTemplate>
<!-- The text binding here is refered to the property name set above in the propertyGroupDescrition -->
<TextBlock x:Name="text" Background="{StaticResource DateGroup_Background}" FontWeight="Bold" Text="{Binding Path=Name}"
Foreground="White"
Margin="1"
Padding="4,2,0,2"/>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
<Style x:Key="ListItemStyle" TargetType="{x:Type ListViewItem}">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<!--
Bind the IsSelected property of a ListViewItem to the
IsSelected property of a ReconciliationTaskViewModel object.
-->
<Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay}" />
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="ItemsControl.AlternationIndex" Value="1" />
<Condition Property="IsSelected" Value="False" />
<Condition Property="IsMouseOver" Value="False" />
</MultiTrigger.Conditions>
<Setter Property="Background" Value="#EEEEEEEE" />
</MultiTrigger>
</Style.Triggers>
</Style>
The cause of the problem is that the ContextMenu isn't part of either the logical or visual tree of the ListView, so RelativeSource/FindAncestor doesn't work, and the DataContext is not inherited.
I posted a solution to this problem a few months ago, you can use it as follows:
<ListView ...>
<ListView.Resources>
<local:BindingProxy x:Key="proxy" Data="{Binding}" />
</ListView.Resources>
...
<ListView.ContextMenu>
<ContextMenu Name="ListViewContextMenu">
<MenuItem Header="Run" Command="{Binding Source={StaticResource proxy}, Path=Data.RunCommand}"/>
</ContextMenu>
</ListView.ContextMenu>
...
</ListView>

Categories