C# MVVM ListBox-根据项目的索引更改项目的背景

C# MVVM ListBox-根据项目的索引更改项目的背景,c#,wpf,mvvm,C#,Wpf,Mvvm,我有一个用脚本语言表示文本行的列表框。我需要“单步”脚本,突出显示当前脚本行(比如说绿色背景) modelview有一个“CurrentLine”属性,它是当前行的索引,因此我想我应该在ItemContainerStyle上写一个触发器,并使用转换器来确定列表框项的索引是否与CurrentLine相同。但是我很难将当前行值传递给转换器,因为它来自VM,我不能将非常量值作为参数传递给转换器。我也不能用触发器的“值”这样做。如何将这些值传入?作为引用类型公开的CURRENTLINE 在我看来,修改V

我有一个用脚本语言表示文本行的列表框。我需要“单步”脚本,突出显示当前脚本行(比如说绿色背景)


modelview有一个“CurrentLine”属性,它是当前行的索引,因此我想我应该在ItemContainerStyle上写一个触发器,并使用转换器来确定列表框项的索引是否与CurrentLine相同。但是我很难将当前行值传递给转换器,因为它来自VM,我不能将非常量值作为参数传递给转换器。我也不能用触发器的“值”这样做。如何将这些值传入?

作为引用类型公开的CURRENTLINE

在我看来,修改ViewModel以将当前行保存为实际的
LineViewModel
(或其他任何内容,取决于虚拟机显示行的方式),而不是保存所选索引是更干净的解决方案

然后,您可以使用多重绑定和检查相等性的转换器来定义触发器:

<ListBox ItemsSource="{Binding Lines}" x:Name="List">
    <ListBox.Resources>
        <sample:EqualityConverter x:Key="Converter" />
    </ListBox.Resources>
    <ListBox.ItemContainerStyle>
        <Style TargetType="Control">
            <Style.Triggers>
                <DataTrigger Value="True">
                    <DataTrigger.Binding>
                        <MultiBinding Converter="{StaticResource Converter}">
                            <Binding Path="DataContext.CurrentLine" ElementName="List" />
                            <Binding />
                        </MultiBinding>
                    </DataTrigger.Binding>
                    <Setter Property="Background" Value="Blue"></Setter>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </ListBox.ItemContainerStyle>
</ListBox>
就这样


CURRENTLINE作为字符串(值类型)公开

如果仍要使用整数索引,可以使用
alternationandex
。将列表的
AlternationCount
设置为其项数,以确保每个项都有其唯一的索引,然后绑定到ListBoxItem的附加属性
ItemsSource.AlternationIndex
。这样,您就不会混淆具有相同内容的行

<ListBox ItemsSource="{Binding Resources}" x:Name="List" AlternationCount="{Binding Resources.Count}">
    <ListBox.Resources>
        <sample:EqualityConverter x:Key="Converter" />
    </ListBox.Resources>
    <ListBox.ItemContainerStyle>
            <Style TargetType="{x:Type ListBoxItem}">
            <Style.Triggers>
                <DataTrigger Value="True">
                    <DataTrigger.Binding>
                        <MultiBinding Converter="{StaticResource Converter}">
                            <Binding Path="DataContext.CurrentItem" ElementName="List"/>
                                <Binding RelativeSource="{RelativeSource Self}" Path="(ItemsControl.AlternationIndex)"/>
                        </MultiBinding>
                    </DataTrigger.Binding>
                    <Setter Property="Background" Value="Blue"></Setter>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </ListBox.ItemContainerStyle>
</ListBox>

是否必须在VM中存储索引,或者是否可以将当前行保存为与Lines集合中的对象相同的类型?目前,Lines集合为List。我想我可以写
类行{string text;bool isCurrent;}
这就是你的想法吗?@JulianGold no我想他的意思是让你的
CurrentLine
属性类型为
string
。因此,在您的
ListBoxItem
样式中,只需检查
CurrentLine
是否与该项目的
{Binding.}
匹配,您就得到了匹配项。@Viv可能有多个脚本行匹配相同?这就是我的意思。如果您的行集合是一个,比如说,ObservableCollection,那么您可以将CurrentLine设置为字符串,而不是整数。如果存在多个相同的脚本行,这仍然有效吗?@JulianGold:不,您需要将这些行包装在一些自定义对象中,然后它就可以工作了。谢谢Marc-这里有一点小精灵的灰尘:-)
<ListBox ItemsSource="{Binding Resources}" x:Name="List" AlternationCount="{Binding Resources.Count}">
    <ListBox.Resources>
        <sample:EqualityConverter x:Key="Converter" />
    </ListBox.Resources>
    <ListBox.ItemContainerStyle>
            <Style TargetType="{x:Type ListBoxItem}">
            <Style.Triggers>
                <DataTrigger Value="True">
                    <DataTrigger.Binding>
                        <MultiBinding Converter="{StaticResource Converter}">
                            <Binding Path="DataContext.CurrentItem" ElementName="List"/>
                                <Binding RelativeSource="{RelativeSource Self}" Path="(ItemsControl.AlternationIndex)"/>
                        </MultiBinding>
                    </DataTrigger.Binding>
                    <Setter Property="Background" Value="Blue"></Setter>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </ListBox.ItemContainerStyle>
</ListBox>
public class EqualityConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        return Equals(values[1], values[0] );
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}