c# wpf - cannot set both DisplayMemberPath and ItemTemplate - c#

I want to add tooltip in listboxItem but it starts problem when there is DisplayMemberPath. Error message said:
cannot set both DisplayMemberPath and ItemTemplate.
When I removed DisplayMemberPath, tooltip in each list item is working. But i dont want to remove DisplayMememberPath because I need it. How to solve this problem?
<ListBox x:Name="lstToys" Style="{DynamicResource ListBoxStyle1}"
ItemsSource="{Binding Strings}" DisplayMemberPath="Toys"
MouseDoubleClick="lstToys_MouseDoubleClick">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" ToolTip="Here is a tooltip"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

DisplayMemberPath is, in effect, a template for a single property, shown in a TextBlock. If you set:
<ListBox x:Name="lstToys" Style="{DynamicResource ListBoxStyle1}"
ItemsSource="{Binding Strings}" DisplayMemberPath="Toys">
</ListBox>
It is equivalent to:
<ListBox x:Name="lstToys" Style="{DynamicResource ListBoxStyle1}"
ItemsSource="{Binding Strings}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Toys}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
You can simply remove the DisplayMemberPath path and use the value in your DataTemplate's Binding:
<ListBox x:Name="lstToys" Style="{DynamicResource ListBoxStyle1}"
ItemsSource="{Binding Strings}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Toys}" ToolTip="Here is a tooltip!"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Edit
If you want to set a ToolTip but keep the DisplayMemberPath, you can do it at the ItemContainerStyle:
<ListBox x:Name="lstToys" Style="{DynamicResource ListBoxStyle1}"
ItemsSource="{Binding Strings}" DisplayMemberPath="Toys">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="ToolTip" Value="Here's a tooltip!"/>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
I'd advise against it. Remember that use DisplayMemberPath stops you from any complex binding in your data template.

Related

How to collapse contents of a databound ListBoxItem when a button is clicked in WPF MVVM

I have a ListBox in my WPF MVVM app using the following code:
<GroupBox Grid.Column="0" Margin="0,0,0,-58">
<DockPanel>
<TextBlock DockPanel.Dock="Top"
HorizontalAlignment="Center"
Margin="0,0,0,8"
FontWeight="Bold"
Text="{x:Static p:Resources.AvaliableLEDsLabel}" />
<ListBox Name="AvailableLEDsListbox" SelectionMode="Extended"
dd:DragDrop.IsDragSource="True"
dd:DragDrop.IsDropTarget="True"
dd:DragDrop.DropHandler="{Binding}"
ItemTemplate="{StaticResource DataTemplateListBoxItem}"
ItemsSource="{Binding AvailableLeds}"
ScrollViewer.VerticalScrollBarVisibility="Hidden"
>
<ListBox.GroupStyle>
<StaticResource ResourceKey="StyleListBoxGroup" />
</ListBox.GroupStyle>
</ListBox>
</DockPanel>
</GroupBox>
This displays grouped lists of devices, with LEDs under them. The DataTemplate is the following:
<GroupStyle x:Key="StyleListBoxGroup">
<GroupStyle.HeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Button Command="{Binding HideGroupCommand}">X</Button>
<TextBlock VerticalAlignment="Center"
HorizontalAlignment="Left"
FontWeight="Bold"
Text="{Binding Name}" />
</StackPanel>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
<DataTemplate x:Key="DataTemplateListBoxItem">
<TextBlock x:Name="LedId" Text="{Binding LedId}"/>
</DataTemplate>
I would like to make the X button in the header hooked up to the HideGroupCommand toggle the hiding of all the items under that particular header. How would I go about doing this? Thanks in advance.
You have few options.
First one :
You would need to have a property in your view model something like 'ListBoxVisibility' then u would bind that property to your UI. In command text u just changed visibility property of that property in view model- so u have it reflected on UI. This visibility property can be of type 'bool' , or 'Visibility' or whatever. Only if it's type of Visibility u don't need converter when binding.
NOTE : Some people use it - even though it kinda goes out of general principel of MVVM patter. But sometimes u have to do it.
Second
If wanna stick to MVVM , then u need to fully separate your UI from your viewmodel. Create click event and change visibility.

WPF : adding a Button as "Show More" where on click of it would load remaining items in the itemControl which is already in Binding a Collection

I am bit new to WPF (XAML) and I have an ItemsControl bound to a list with a MyCollections property . Now my requirement is initially to show only 1st element from the list and having a Show More button option at the end of list. A click on it would show the rest of the items from the collection.
This is my XAML so far, displaying the whole collection:
<ItemsControl x:Name="ContentRoot" ItemsSource="{Binding MyCollections}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<grid>
<TextBox Text="{Binding }" />
<TextBox Text="{Binding }" />
</grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
You can have both a ContentControl (which displays the first item of the collection) and an ItemsControl (which displays the whole collection) displayed only when a ToggleButton is checked for example.
<StackPanel>
<StackPanel.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
<DataTemplate DataType="{x:Type local:MyViewModel}">
<Grid>
<TextBox Text="{Binding}" />
</Grid>
</DataTemplate>
</StackPanel.Resources>
<ContentControl Content="{Binding MyCollection[0]}"/>
<ToggleButton x:Name="toggle" Content="Show more"/>
<ItemsControl ItemsSource="{Binding MyCollection}" Visibility="{Binding ElementName=toggle, Path=IsChecked, Converter={StaticResource BooleanToVisibilityConverter}}"/>
</StackPanel>
You can then adapt this to fit your exact needs.

Change visibility of one itemscontrol via checkbox in another

I have two ItemsControls with the same ItemsSource. One has some controls for each item, the other has a checkbox for each item. The controls in them are dynamically added. How can I bind the visibility of the first ItemsControls to the corresponding checkbox in the other ItemsControls ?
Here's the first ItemsControl containing multiple TextBlocks in the row. Note: I want to hide the whole row of controls.
<ItemsControl ItemsSource="{Binding VehicleCollection}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock />
<TextBlock />
<TextBlock />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Here's the second ItemsControl with the checkboxes:
<ItemsControl ItemsSource="{Binding VehicleCollection}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<CheckBox Content="{Binding Name}"
IsChecked="True" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
So what happens is, for each item in VehicleCollection, a new row of textblocks is added for the first ItemsControl, and a checkbox is added for the second ItemsControl. These should relate to each other for example: If I uncheck the first checkbox, the first row for the other ItemsControl should be hidden.
I know how to do the booltovis converter, just not sure on how to relate these two ItemsControls.
Edit: These are both in the mainwindow.xaml by the way.
In order to show or hide an item of the first ItemsControl, add an IsVisible property to your Vehicle class (i.e. the element type of the VehicleCollection) and bind the Visibility of the item's ContentPresenter to the IsVisible property in an ItemContainerStyle:
<ItemsControl ItemsSource="{Binding VehicleCollection}">
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Visibility"
Value="{Binding IsVisible,
Converter={StaticResource BooleanToVisibilityConverter}}"/>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
...
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
In the other ItemsControl, bind the IsChecked property of the CheckBox to the IsVisible property:
<ItemsControl ItemsSource="{Binding VehicleCollection}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Name}" IsChecked="{Binding IsVisible}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Of course make sure that class Vehicle implements INotifyPropertyChanged and fires the PropertyChanged event when the IsVisible property changes.
You should be able to manage this by adding a boolean Property in your Vehicle class, which I presume is the basis for your VehicleCollection. Something like: IsSelected.
Then you can modify your XAML as shown below:
<ItemsControl ItemsSource="{Binding VehicleCollection}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Visibility="{Binding IsSelected,Converter={StaticResource boolToVisConverter}}"/>
<TextBlock Visibility="{Binding IsSelected,Converter={StaticResource boolToVisConverter}}"/>
<TextBlock Visibility="{Binding IsSelected,Converter={StaticResource boolToVisConverter}}"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<ItemsControl ItemsSource="{Binding VehicleCollection}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<CheckBox Content="{Binding Name}"
IsChecked="{Binding IsSelected}" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
This is untested XAML, as I just typed it into the answer. Might need a tweak.

How can i make a ListView's items take up all the available height?

I am trying to make a column chart using WPF. For the Y axis I have a list of values which I would like to display on the control.
I have a ListView bound to the collection. How can I get the items to spread over the entire length of the list view rather then squish together at the top? And is the ListViewthe correct control to use for this?
Here is a sample of my Xaml:
<ListView Grid.Row="1" Grid.Column="1" Grid.RowSpan="2"
ItemsSource="{Binding YAxisValues}"
Background="Gray" VerticalContentAlignment="Stretch">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Label Content="{Binding Path=Value}"
Foreground="White"
HorizontalAlignment="Left"
FontSize="12" Width="50"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
On the left is the list view as i currently have it.
On the right is my desired result.
How can I change my ListView to get there? Or do I need to use a different control entirely?
with UniformGrid used as ItemsPanel items get equal height
<ListView Name="Axis" Grid.Row="1" Grid.Column="1" Grid.RowSpan="2"
ItemsSource="{Binding YAxisValues}"
Background="Gray" VerticalContentAlignment="Stretch"
ScrollViewer.VerticalScrollBarVisibility="Disabled">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="1"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<!--no changes-->
</ListView.ItemTemplate>
</ListView>
there can be a issue when ListView doesn't have enough height for all elements. In that case I would put ListView into ViewBox
Set HorizontalContentAlignment to Stretch for items.
<ListView>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListView.ItemContainerStyle>
</ListView>

Items in ListBox not automatically updating

The problem is that the user interface (the ListBox) is not updated when new items enter its collection. I've a ListBox which is defined as follows:
<ListBox x:Name="ui_UserList" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" SelectionChanged="ui_UserList_SelectionChanged" ItemsSource="{Binding chatUsers}" Grid.ColumnSpan="3" Margin="10,179,10,81" DataContext="{Binding}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Background="Transparent">
<TextBlock Text="{Binding nickname}" HorizontalAlignment="Center" TextAlignment="Center" FontSize="42" Grid.Row="0" Grid.Column="0" Foreground="Black" VerticalAlignment="Top" TextWrapping="Wrap"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The itemsource ChatUsers is an ObservableCollection. This was originally designed as an application for Windows Phone 8, where the ListBox equivalent works as expected (it updates when an item enters the collection).
Is there something about the ListBox that I've missed?
Ok, looks like I needed to set the DataContext explicitly even though it never complained about it.
The only change is this:
<ListBox x:Name="ui_UserList" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" SelectionChanged="ui_UserList_SelectionChanged" ItemsSource="{Binding chatUsers}" Grid.ColumnSpan="3" Margin="10,179,10,81" DataContext="{StaticResource ChatUsersViewModel}">
.....
</ListBox>

Categories

Resources