How to have first item bolded in ListBox?

2019-07-29 21:43发布

问题:

I have a ListBox in which I would like to have only the first item bolded.

View:

<ListBox x:Name="lstBox" ItemsSource="{Binding List}" DisplayMemberPath="{Binding SequencesDisplayLanguage}" />

Viewmodel:

private ObservableCollection<Sequence> _list = new ObservableCollection<Sequence>() { };
public ObservableCollection<Sequence> List { get { return _list; } }

private string _sequencesDisplayLanguage = "NameEnglish";
public string SequencesDisplayLanguage
{
    get
    {
        return _sequencesDisplayLanguage;
    }
    set
    {
        _sequencesDisplayLanguage = value;
        OnPropertyChanged("SequencesDisplayLanguage");
    }
}

Model:

public class Sequence : INotifyPropertyChanged
{
    public Sequence()
    {
        NameEnglish = "";
        NameRomanian = "";
    }

    private string _nameEnglish;
    public string NameEnglish
    {
        get
        {
            return _nameEnglish;
        }
        set
        {
            _nameEnglish = value;
            OnPropertyChanged("NameEnglish");
        }
    }
    private string _nameRomanian;
    public string NameRomanian
    {
        get
        {
            return _nameRomanian;
        }
        set
        {
            _nameRomanian = value;
            OnPropertyChanged("NameRomanian");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

I've tried using a ItemTemplate, with a converter which returns FontWeights.Bold if the item is of a particular type (I've taken care to put that particular item first in the list so it will be bolded). The code is this:

<ListBox.ItemTemplate>
  <DataTemplate>
    <TextBlock FontWeight="{Binding Converter={StaticResource sequenceToFontWeightConverter}}"
                       Text="{Binding Path=NameEnglish}" />
  </DataTemplate>
</ListBox.ItemTemplate>

but I need to be able to change the text binding path at runtime (NameEnglish or NameRomanian). So I've tried referencing the property in the Viewmodel:

Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Grid}}, Path=DataContext.SequencesDisplayLanguage}"/>

but it doesn't work (if SequencesDisplayLanguage=="NameEnglish" then all ListBox items show up as "NameEnglish").

So, how can I bold only the first item in the ListBox while being able to change binding path at runtime?

UPDATE

I tried Clemens' solution, but now the selected item highlighting has changed: the item has a larger height, a rectangle with border and different color appears when selecting (see picture).

How can I keep the original item size and highlighting?

UPDATE 2

Found out:

<Style TargetType="ListBoxItem" BasedOn="{StaticResource {x:Type ListBoxItem}}">

回答1:

You could style a ListBoxItem based on its index by setting a Trigger on its AlternationIndex attached property. You would also have to set a large enough value for the AlternationCount property:

<ListBox ItemsSource="{Binding List}" AlternationCount="2147483647">
    <ListBox.ItemContainerStyle>
        <Style TargetType="ListBoxItem">
            <Style.Triggers>
                <Trigger Property="ItemsControl.AlternationIndex" Value="0">
                    <Setter Property="FontWeight" Value="Bold"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </ListBox.ItemContainerStyle>
</ListBox>


回答2:

How are you ordering the list to make sure the item you want is first? The order of items in an ObservableCollection's is the order they were added in.

If you have a sequence number as a property of the list members then you can simply change your converter to bind to that and return "bold" if the sequence number is 0 and "normal" otherwise.