Ok, I've got a ListView. I've set ItemsSource from code. This ListView has Property SelectionMode="Multiple". But I'd like to disable some items from selecting.
XAML: //not working
<ListView x:Name="MyListView" SelectionMode="Multiple">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="IsEnabled" Value="{Binding Path=enabled, Mode=TwoWay}" />
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<!-- my template -->
</ListView.ItemTemplate>
</ListView>
Although, I cannot set each ListViewItem from code...
You can try using a Converter? See this easy tutorial.
Related
I have some defined XAML that looks like
<ListView ItemsSource="{Binding ConfigItems,Mode=OneWay}" Margin="5">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
</Style>
</ListView.ItemContainerStyle>
<ItemsControl
ItemsSource="{Binding}"
ItemTemplateSelector="{StaticResource ConfigItemDataSelector}"/>
</ListView>
Now I realize that this isn't how it should be but that is the source of the question. As is I get an exception that indicates the ItemsSource should be empty before using it. From a question asked 12 years ago I see that this exception is raised when Items and ItemsSource properties are being used at the same time. So I set out to use one or the other. But I get this error when I define it like above or when I leave ItemsSource out altogether. When I try to use Items I get an error at compile time that indicates the list has to have a setter.
In case there is some confusion the ConfigItemDataSelector looks like basically returns a DataTemplate depending on which view model is being used. But I think looking at the selector is a distraction from the problem.
public sealed class ConfigItemDataSelector : DataTemplateSelector
{
public DataTemplate MeasurementDataTemplate { get; set; }
. . .
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
if (item is MeasurementConfigItemViewModel)
{
return MeasurementDataTemplate;
}
else if (item is LEDFeedbackConfigItemViewModel)
{
return LEDFeedbackDataTemplate;
}
. . .
return null;
}
}
So how should the ListView use the ItemsControl?
You can not put ItemsControl in ListView.Items
Try this
<ListView ItemsSource="{Binding ConfigItems,Mode=OneWay}" Margin="5">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding}"
ItemTemplateSelector="{StaticResource ConfigItemDataSelector}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
You can see source code in referencesource.microsoft.com
The ItemsControl have DefaultPropertyAttribute("Items"), so if you do not declare what property you used in xaml, it will set to ListView.Items be equal
<ListView ItemsSource="{Binding ConfigItems,Mode=OneWay}" Margin="5">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
</Style>
</ListView.ItemContainerStyle>
<ListView.Items>
<ItemsControl
ItemsSource="{Binding}"
ItemTemplateSelector="{StaticResource ConfigItemDataSelector}"/>
</ListView.Items>
</ListView>
And throw exception say "ItemsSource should be empty before using it"
I found through trial and error that the following works
<ListView Margin="5">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
</Style>
</ListView.ItemContainerStyle>
<ItemsControl
ItemsSource="{Binding ConfigItems}"
ItemTemplateSelector="{StaticResource ConfigItemDataSelector}"/>
</ListView>
Basically taking the ItemsSource property from the ListView and moving it to the ItemsControl.
When I use ScrollIntoView for my listview, The page goes blank for a moment and then rerenders, how can I make this more smooth?
Here is my current code:
<ListView Name="MessageList" Margin="0,82,0,45"
SelectionMode="None"
IsItemClickEnabled="True"
ItemClick="FileMessage_Click"
HorizontalAlignment="Stretch"
ItemTemplateSelector="{StaticResource MsgDataTemplateSelector}"
ItemsSource="{x:Bind messages}" >
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListView.ItemContainerStyle>
</ListView>
And in the code-behind I have this each time a new message is added to the observable collection that feeds into the listview:
MessageList?.ScrollIntoView(MessageList.Items[MessageList.Items.Count -1]);
I didn't reproduced your problem completely. On my PC, this problem only occurs at the first time I add item to ListView. ListView use ItemsStackPanel as its default panel, which supports UI Virtualization. After changing the default panel to StackPanel which has no support for UI Virtualization, the problem doesn't appear.
You can change the ItemsPanel of ListView like below:
<ListView Name="MessageList" Margin="0,82,0,45"
SelectionMode="None"
Height="300"
IsItemClickEnabled="True"
HorizontalAlignment="Stretch"
ItemsSource="{x:Bind messages}" >
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel></StackPanel>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListView.ItemContainerStyle>
</ListView>
Update: To scroll to the last Item, you need to set the height of ListView and call ListView.UpdateLayout before ScrollIntoView:
MessageList.UpdateLayout();
MessageList.ScrollIntoView(MessageList.Items[MessageList.Items.Count - 1]);
I have a ListView bound with an ObservableCollection. The Itemtemplate of the ListView is the following:
<ListView ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True" PreviewMouseLeftButtonUp="ListViewClicked" PreviewKeyDown="NameBox_KeyDown">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="./Resources/DeleteIcon.png"/>
<TextBox Text="{Binding Path=Name}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
This way I give the user the choice to either change the name of the element, or delete it from the list. I handle this two operations in code behind through the two event handlers attached to the ListView.
The problem is that when I click on the TextBox, the SelectedItems property of the ListView doesn't change and it points the last selected item. When I click on the image or on the free space around the selection change.
Now I have two questions:
Is there an easy way to fix this behavior?
Is it possible to get a reference to the collection item whose property is exposed by the TextBox?
One way to deal with this problem is to set Trigger to set IsSelected when keyboard focus is within ListViewItem
<ListView ... SelectionMode="Single">
<!-- .... -->
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Style.Triggers>
<Trigger Property="IsKeyboardFocusWithin" Value="True">
<Setter Property="IsSelected" Value="True"/>
</Trigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
</ListView>
Is it possible to select single words with the mouse in a WPF ListBox control? When yes, how can I do that?
All hints are welcome :)
If you define an ItemTemplate for your ListBox, you can use a TextBox to display each item (assuming that your items are plain strings):
<ListBox ItemsSource="{Binding YourCollection}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding}" IsReadOnly="True" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
UPDATE >>>
I just tested it and had to make one change to set the Binding.Mode property to OneWay and it worked just fine. However, I noticed that the TextBox would stop each item from being selected, so added a Style to take care of that and styled the items a little bit too:
<ListBox ItemsSource="{Binding YourCollection}" Name="ListBox" HorizontalContentAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding ., Mode=OneWay}" IsReadOnly="True">
<TextBox.Style>
<Style>
<Setter Property="TextBox.BorderThickness" Value="0" />
</Style>
</TextBox.Style>
</TextBox>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemContainerStyle>
<Style>
<Style.Triggers>
<Trigger Property="ListBox.IsKeyboardFocusWithin" Value="True">
<Setter Property="ListBoxItem.IsSelected" Value="True" />
</Trigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
Currently i have a user control which contains a listbox of other visual element user controls; which (for this special case) have been data templated.
<Grid>
<ListBox ItemSource="{Binding Path=UserControlCollection}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<ContentPresenter Content="{Binding}"/>
<Button/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
The issue is that i have This Issue. And because of the data template, i can't seem to find a way to correct the styling issue.
Any help would be greatly appreciated.
I found by overriding the ListBoxItem's horizontalcontentalignment and verticalcontentalignment i was able to correct the issue.
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
</Style>
</ListBox.ItemContainerStyle>
I also found changing to a listview helpful but did have issues of its own.