I'm trying to create fancy looking Listbox. ListBoxItems are supposed to expand after being selected, but the problem is, they're also supposed to contain another ListBox filled with some details about particular item and I have no idea how to put some data into it.
I've tried both accessing it from C# code and binding it in XAML but I'm still nowhere near the solution.
<UserControl.Resources>
<ResourceDictionary>
<DataTemplate x:Key="SelectedTemplate">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path = Order}" Style="{StaticResource SampleListCellItem}" MinWidth="35"/>
<TextBlock Text="{Binding Path = FullName}" Style="{StaticResource SampleListCellItem}" Width="340"/>
<TextBlock Text="{Binding Path = FirstName}" Style="{StaticResource SampleListCellItem}" Width="200" />
<TextBlock Text="{Binding Path = BirthDate, StringFormat = d}" Style="{StaticResource SampleListCellItem}" Width="100"/>
</StackPanel>
<StackPanel HorizontalAlignment="Right">
<ListBox Name="InnerList" Height="200" Width="200"/>
<Button Name="Button1" Height="40" Width="100" Content="ButtonText" Visibility="Visible"/>
</StackPanel>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="ItemTemplate">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path = Order}" Style="{StaticResource SampleListCellItem}" MinWidth="35"/>
<TextBlock Text="{Binding Path = FullName}" Style="{StaticResource SampleListCellItem}" Width="340"/>
<TextBlock Text="{Binding Path = FirstName}" Style="{StaticResource SampleListCellItem}" Width="200" />
<TextBlock Text="{Binding Path = BirthDate, StringFormat = d}" Style="{StaticResource SampleListCellItem}" Width="100"/>
</StackPanel>
</StackPanel>
</DataTemplate>
<Style TargetType="{x:Type ListBoxItem}" x:Key="ContainerStyle">
<Setter Property="ContentTemplate" Value="{StaticResource ItemTemplate}"/>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="ContentTemplate" Value="{StaticResource SelectedTemplate}"/>
</Trigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
</UserControl.Resources>
It sounds like what you're looking for is a tree. I think the TreeView control would be ideal for what you're looking for.
In your item that you want to display, I assume you have a property that is a list (of T) or other type that is compatible with a normal listbox itemsource. Let name it ListPr for the sake of example.
In your data template, add a listBox control and set the ItemsSource to {Binding Path = ListPr }. It should works just like that. In that new listbox, you will be able to define another data template, and so on.
Like it's mentioned in another post though, a treeview might be what you need in this case.
Hope that helps.
Related
I have the following usercontrol:
<Border
Style="{StaticResource notificationBarBorderStyle}"
Height="21"
>
<StackPanel
Orientation="Horizontal"
Style="{StaticResource notificationBarStyle}"
>
<DockPanel>
<Image
Width="17"
Height="16"
Margin="4,0,11,0"
Source="{Binding ElementName=NotificationControl, Path=ImageSource}"
/>
<TextBlock
x:Name="notificationTextBlock"
VerticalAlignment="Center"
Style="{StaticResource textBlockStyle}"
Text="{Binding ElementName=NotificationControl, Path=Message}"
/>
</DockPanel>
</StackPanel>
</Border>
and then in another usercontrol i try to reference it like so:
<Controls:NotificationBarControl
Grid.Row="2"
Grid.Column="0"
DataContext="{Binding IncomingResult}"
Message="{Binding TaskResultsMessage}"
Visibility="{Binding Path=ShowTaskResults, Converter={StaticResource boolToHiddenVisibilityConverter}}"
Command="{Binding DisplayTaskError}"
ImageSource="{DynamicResource somePicture1}"
>
I want to be able to put a data trigger on the image source so that depending on the state of a boolean flag, a different image will appear (call it somePicture2). I do not really want to do much to change the control itself, as it is referenced a few times in a rather large project and I do not want to break anything.
You could set the Style property of the control to a Style with a DataTrigger that binds to your bool property:
<Controls:NotificationBarControl
Grid.Row="2"
Grid.Column="0"
DataContext="{Binding IncomingResult}"
Message="{Binding TaskResultsMessage}"
Visibility="{Binding Path=ShowTaskResults, Converter={StaticResource boolToHiddenVisibilityConverter}}"
Command="{Binding DisplayTaskError}">
<Controls:NotificationBarControl.Style>
<Style TargetType="Controls:NotificationBarControl">
<Setter Property="ImageSource" Value="{StaticResource somePicture1}" />
<Style.Triggers>
<DataTrigger Binding="{Binding YourBooleanSourceProperty}" Value="True">
<Setter Property="ImageSource" Value="{StaticResource somePicture2}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Controls:NotificationBarControl.Style>
</Controls:NotificationBarControl>
I have two questions.
Q1: I have a ListView and I want OnSelectedItem to expand the attributes and show more attributes. Is this possible? How? [I have the attributes in the ObservableCollection]
Q2: I want to put a clickable image inside the view, that will change ViewModel (chat behavior). Is this possible? How?
ListView
<ListView x:Name="dataGrid" ItemsSource="{Binding Friends}" Height="314" BorderThickness="0" SelectedItem="{Binding SelectedItemFriends}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="Resources\Images\ic_status.png" Height="24" Width="18"/>
<StackPanel Margin="5" Orientation="Vertical">
<TextBlock FontWeight="Bold" Text="{Binding name}"/>
<TextBlock Text="{Binding lastLocation}"/>
<TextBlock Text="{Binding timestamp}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
A1: In datatemplate, create how you would like the extended attributes to appear and place them in a container such as a stack panel.
Then use an DataTrigger using the IsSelected property to change the visibility of the stack panel container from visible and collapsed as needed.
A2: The easiest way would be to use a Button with the content source set to an image as this will give you the click event/command binding to play with.
EDIT: Example of the first answer could look like:
<ListView x:Name="dataGrid" Height="314" BorderThickness="0" SelectedItem="{Binding SelectedItemFriends}" ItemsSource="{Binding Friends}" >
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" >
<Image Source="Resources\Images\ic_status.jpg" Height="24" Width="18"/>
<StackPanel Margin="5" Orientation="Vertical">
<TextBlock FontWeight="Bold" Text="{Binding Name}"/>
<StackPanel x:Name="AdditionItems" Orientation="Vertical" Visibility="Collapsed">
<TextBlock Text="{Binding LastLocation}"/>
<TextBlock Text="{Binding TimeStamp}"/>
</StackPanel>
</StackPanel>
</StackPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListViewItem}}, Path=IsSelected}" Value="true">
<Setter TargetName="AdditionItems" Property="Visibility" Value="Visible"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I have run this code and it works for me, it should be enough to put you on the right track. The important things to note are that the trigger is attached to the ListViewItem, it will trigger when it the IsSelected property turns true, it will then change the visibility of the StackPanel called "Additional Items" to visible from collapsed.
I have issue, i just try to make chat window with messages(From right incoming and from left sended out) but seems like stackpanel ignore HorizontalAlignment. Here's my code
<ListView>
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<StackPanel HorizontalAlignment="Left">
<TextBlock TextWrapping="Wrap"
FontSize="22"
Text="{Binding MessageTextIn}"
/>
<TextBlock
FontSize="10"
Text="{Binding MessageTimeIn}" Padding="10"
/>
</StackPanel>
<StackPanel HorizontalAlignment="Right">
<TextBlock TextWrapping="Wrap"
FontSize="22"
Text="{Binding MessageTextOut}"
/>
<TextBlock
FontSize="10"
Text="{Binding MessageTimeOut}" Padding="10"
/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Seems like i do something wrong but what exactly?
Thanks for any help!
Sorry if i ask something stupid.
That is because your ItemContainer only has a right alignment (by default).
Set the ItemContainerStyle of your Listview:
<ListView>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalAlignment" Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
</ListView>
I have two things I'm trying to achieve:
Add a horizontal separator between listbox items in WPF.
Don't show the separator at the bottom of the final listbox item.
My current layout is pictured here:
This shows 2 listbox items (though I have no way of knowing how many items could potentially be generated). I would like them separated by a horizontal separator, except on the last listbox item so there isn't a spare separator at the bottom of the pane. How can I achieve this in XAML? See my current XAML here:
<TabItem Header="Third Party Updates">
<Grid>
<TextBlock Name="ThirdPartyNoManifestTextBox" Width="Auto" HorizontalAlignment="Left" Margin="267,22,0,0" TextWrapping="Wrap" Text="{Binding Path=WindowsUpdateCompliance, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" FontSize="14" Foreground="DarkSlateBlue"/>
<Button Name="CheckforThirdPartyUpdatesButton" Content="Check for Third Party Updates" Margin="10,11,339,304" Click="CheckforThirdPartyUpdatesButton_Click" MaxWidth="200" Grid.Column="1" Grid.Row="1"/>
<ListBox Name="ThirdPartyListBox" ItemsSource="{Binding}" Margin="0,70,0,0">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Button Name="ThirdPartyInstallButton" Content="Install" Click="InstallThirdPartyUpdatesButton_Click" Margin="5,5,0,0" Height="25"></Button>
<Button Name="ThirdPartyPostoneButton" Content="Postpone" Click ="PostponeThirdPartyUpdatesButton_Click" Margin="5,5,0,0" Height="25"></Button>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Label Content="•" Grid.Row="1" VerticalContentAlignment="Center"/>
<Label Content="•" Grid.Row="2" VerticalContentAlignment="Center"/>
<Label Content="•" Grid.Row="3" VerticalContentAlignment="Center"/>
<Label Content="•" Grid.Row="4" VerticalContentAlignment="Center"/>
<StackPanel Orientation="Horizontal" Grid.Column="1">
<Label Name="MissingRequiredAppGenericTextBlock" VerticalAlignment="Center" Content="Required application update detected:" FontWeight="SemiBold" FontSize="12"/>
<Label Name="RequiredAppNameTextBlock" VerticalAlignment="Center" Content="{Binding Item2.Name}" Foreground="MidnightBlue" FontSize="13"/>
<Label Grid.Column="1" Grid.Row="1" Name="RequiredAppVersionTextBlock" Content="{Binding Item2.RequiredVersion}" VerticalAlignment="Center" Foreground="MidnightBlue" FontSize="13"/>
</StackPanel>
<TextBlock Grid.Column="1" Grid.Row="1" Name="RequiredAppCustomUIMessageTextBlock" Text="{Binding Item2.CustomUIMessage}" TextWrapping="Wrap" VerticalAlignment="Center"/>
<TextBlock Grid.Column="1" Grid.Row="2" VerticalAlignment="Center">
<Hyperlink Name="Link" NavigateUri="{Binding Item2.TT}" RequestNavigate="Hyperlink_RequestNavigate">
<TextBlock Text="{Binding Item2.TT}"/>
</Hyperlink>
</TextBlock>
<StackPanel Orientation="Horizontal" Grid.Column="1" Grid.Row="3">
<TextBlock Text="The following processes will be closed prior to install: " VerticalAlignment="Center" />
<TextBlock Text="{Binding Item2.ListOfProcessesToClose}" FontWeight="SemiBold" Foreground="Red" VerticalAlignment="Center"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Grid.Column="1" Grid.Row="4">
<TextBlock Text="You have used " VerticalAlignment="Center" />
<TextBlock Text="{Binding Item3.UsedDeferrals}" VerticalAlignment="Center"/>
<TextBlock Text=" of " VerticalAlignment="Center"/>
<TextBlock Text="{Binding Item2.MaxDefferals}" VerticalAlignment="Center"/>
<TextBlock Text=" deferrals for this update." VerticalAlignment="Center"/>
</StackPanel>
</Grid>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding PostponeClicked}" Value="1">
<Setter Property="Visibility" Value="Hidden"></Setter>
</DataTrigger>
<Trigger Property="Control.IsMouseOver" Value="True">
<Setter Property="Control.BorderBrush" Value="SteelBlue" />
<Setter Property="Control.BorderThickness" Value="1" />
</Trigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
</Grid>
</TabItem>
Update
Added suggested separator code. Separator is now present but does not fill the available horizontal space:
You can try to put Separator at the top of each item. With that you don't have unwanted Separator after the last item.
Then use DataTrigger with {RelativeSource PreviousData} binding to hide separator at the top of the first item :
<StackPanel>
<Separator>
<Separator.Style>
<Style TargetType="Separator">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource PreviousData}}" Value="{x:Null}">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Separator.Style>
</Separator>
<StackPanel Orientation="Horizontal">
<Button Name="ThirdPartyInstallButton" Content="Install" Click="InstallThirdPartyUpdatesButton_Click" Margin="5,5,0,0" Height="25"></Button>
<Button Name="ThirdPartyPostoneButton" Content="Postpone" Click ="PostponeThirdPartyUpdatesButton_Click" Margin="5,5,0,0" Height="25"></Button>
<Grid>
.........
.........
</Grid>
</StackPanel>
</StackPanel>
UPDATE :
I can't tell for sure what causes the separator not stretching accross listbox width. Maybe try to set listboxitem's HorizontalContentAlignment to Stretch :
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListBox.ItemContainerStyle>
I am having a problem, I have a datatable data with 3 columns(ID,NAME,QUANTITY), I want to bind it with a ListBox, and make ListBox shows values from column NAME and QUANTITY,otherwise when I double click in a selected item,it will send ID value, here is my XAML:
<ListBox HorizontalAlignment="Left" Margin="6,0,0,0" Name="ListBox1" VerticalAlignment="Top" Height="600" Width="321">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<EventSetter Event="MouseDoubleClick" Handler="ListBox1Item_DoubleClick" />
</Style>
</ListBox.ItemContainerStyle>
<ListBox.Resources>
<DataTemplate x:Key="listBoxTemplate">
<DockPanel >
<TextBlock FontWeight="Bold" Text="{Binding NAME}"
DockPanel.Dock="Left"
Margin="5,0,10,0" Width="100"/>
<TextBlock Text="{Binding QUANTITY} " Foreground="Green" FontWeight="Bold" />
</DockPanel>
</DataTemplate>
</ListBox.Resources>
</ListBox>
Here is my code behind:
...
ListBox1.ItemsSource = data.DefaultView;
ListBox1.SelectedValuePath = "ID";
...
But it does not show anything, something wrongs? please help! thanks for reading this!
You need to set the ListBox.ItemTemplate.
At the moment you are defining a template with a key, that template is not being used anywhere.
<ListBox.ItemTemplate>
<DataTemplate>
<DockPanel >
<TextBlock Text="{Binding NAME}" FontWeight="Bold"
DockPanel.Dock="Left"
Margin="5,0,10,0" Width="100" />
<TextBlock Text="{Binding QUANTITY}" FontWeight="Bold"
Foreground="Green" />
</DockPanel>
</DataTemplate>
</ListBox.ItemTemplate>