WinRT XAML - 如何在列表视图中设置所选项目的样式?

WinRT XAML - how do I style a selected item in a list view?

在我的 WinRT 应用程序中,我想显示状态值列表并突出显示当前状态。显示列表时,它应该是只读的,因此不会与用户交互。尽管我使用的是 ListView,但我希望禁用任何选择功能。我认为禁用 ListView 可以解决这个问题。 但是现在在我后面的代码中有;

  public IList<JobStatusItem> StatusList
    {
        get
        {
            var values = Enum.GetValues(typeof(JobStatus));
            var selected = Status.ToString();
            var i = 0;
            var list = new List<JobStatusItem>();
            foreach (var value in values)
            {
                i++;
                var item = GetStatusDisplay(value.ToString());
                list.Add(new JobStatusItem
                {
                    Id = i,
                    Status = item,
                    Selected = value.ToString().Equals(selected)
                });                    
            }

            return list;
        }
    }

对于我的XAML,我有

                <ListView x:Name="ListStatus" 
                          IsItemClickEnabled="False" 
                          IsSwipeEnabled="False"
                          SelectionMode="Single" 
                          ItemsSource="{Binding Path=AssignedJobs.SelectedDay.SelectedJob.StatusList, Mode=OneWay}"
                          >
                    <ListView.ItemContainerStyle>
                        <Style TargetType="ListViewItem">
                            <Setter Property="IsSelected" Value="{Binding Path=Selected, Mode=OneWay}"/>
                        </Style>
                    </ListView.ItemContainerStyle>

                    <ListView.ItemTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding Path=Status}"></TextBlock>
                        </DataTemplate>
                    </ListView.ItemTemplate>
                </ListView>

而当我 运行 时,选中状态的样式未设置为选中。为什么会这样,我该如何解决?

您代码中的绑定表达式 (<Setter Property="IsSelected" Value="{Binding Path=Selected, Mode=OneWay}"/>) 将不起作用,因为上下文不在项目级别。

由于WinRT中缺少祖先绑定,很难使用纯绑定来实现你想要的;但是,检查 IsSelected 属性 代码隐藏非常简单。最后,如果你想要一个纯粹的 XAML 解决方案,你总是可以将下面的代码包装在 Behavior.

您基本上想要订阅 ListViewContainerContentChanging 事件并手动设置 ItemContainerIsSelected 属性 以匹配 Selected 属性 您的模型 JobStatusItem。像这样 -

    private void OnListViewContainerContentChanging(ListViewBase sender, ContainerContentChangingEventArgs args)
    {
        if (args.ItemContainer != null && !args.InRecycleQueue && args.Phase == 0)
        {
            args.ItemContainer.IsSelected = ((JobStatusItem)args.Item).Selected;

另一种可能的解决方案

由于您想要一个带有突出显示选择的只读列表,因此最好通过将 SelectionMode 设置为 ListView 来完全禁用 ListView 上的任何 clicking/tapping 交互None.

然后在 DataTemplate 中,用 Border 包裹 TextBlock 并在 [=18= 时给 Border 一个不同的 Background ] 属性 是 true.

所以,我了解到您希望 禁用 ListView 中项目的手动选择,同时保持程序选择

实现您正在尝试做的事情的最简单方法是将您的 ListView 定义为 SelectionMode="Single" 并将 SelectedItem 属性 绑定到您的 ViewModel 的相应 属性。要阻止任何手动交互,只需在其上放置一个带有 IsHittestVisible="True" 的网格即可阻止任何手动交互。像下面这样:

<Grid>
    <ListView x:Name="ListStatus"
              SelectionMode="Single"
              ItemsSource="{Binding StatusList}"
              SelectedItem="{Binding SelectedItem}" 
              ItemTemplate="{StaticResource UnselectedListDataTemplate}"/>
    <Grid IsHitTestVisible="True" Background="Transparent" />
</Grid>

不过,我会选择 完全不同的方法

更方便的方法是设置 ListView.SelectionMode="None" 并使用 ItemTemplateSelectorItemContainerStyleSelector 在突出显示版本和正常版本之间切换 template/style版本.

public class JobStatusItemTemplateSelector : DataTemplateSelector
{
    public DataTemplate SelectedTemplate { get; set; }
    public DataTemplate UnselectedTemplate { get; set; }
    protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
    {
        var element = item as JobStatusItem;
        if (element == null) return UnselectedTemplate;
        return element.Selected ? SelectedTemplate : UnselectedTemplate;
    }
}

您的 ListView 定义为:

<Page.Resources>
    <DataTemplate 
        x:DataType="local:JobStatusItem"
        x:Key="SelectedListDataTemplate">
        <TextBlock Text="{Binding Status}" FontWeight="ExtraBold" Foreground="DarkOrchid"/>
    </DataTemplate>
    <DataTemplate 
        x:DataType="local:JobStatusItem"
        x:Key="UnselectedListDataTemplate">
        <TextBlock Text="{Binding Status}" />
    </DataTemplate>
    <local:JobStatusItemTemplateSelector x:Key="ListTemplateSelector" 
                                         SelectedTemplate="{StaticResource SelectedListDataTemplate}" 
                                         UnselectedTemplate="{StaticResource UnselectedListDataTemplate}"/>
</Page.Resources>

<ListView x:Name="ListStatus"
          SelectionMode="None"
          ItemsSource="{Binding StatusList}"
          ItemTemplateSelector="{StaticResource ListTemplateSelector}">
</ListView>

这将使您能够轻松区分已发生、正在进行和将在未来发生的状态步骤,甚至可以让您轻松地将过去发生的错误步骤等内容整合起来。
根据您使用的是 TemplateSelector 还是 StyleSelector,您甚至可以通过不同的模板实现符号、图像等。