【问题标题】:WinRT XAML - how do I style a selected item in a list view?WinRT XAML - 如何在列表视图中设置选定项目的样式?
【发布时间】:2017-07-22 09:22:13
【问题描述】:

在我的 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>

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

【问题讨论】:

    标签: c# xaml windows-runtime


    【解决方案1】:

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

    由于 WinRT 中缺少祖先绑定,因此很难使用纯绑定来实现您想要的;但是,在后面的代码中检查 IsSelected 属性非常简单。归根结底,如果您想要一个纯 XAML 解决方案,您可以随时将下面的代码包装在 Behavior 中。

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

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

    另一种可能的解决方案

    由于您想要一个带有突出显示选择的只读列表,因此最好将ListView 上的任何点击/点击交互设置为SelectionMode 以完全禁用SelectionModeNone

    然后在您的DataTemplate 中,用Border 包裹TextBlock,并在Selected 属性为true 时为Border 赋予不同的Background

    【讨论】:

    • 我选择了“另一种可能”的解决方案,它奏效了。谢谢你。
    【解决方案2】:

    所以,我想您希望在 维护编程选择的同时禁用 ListView 中项目的手动选择

    实现您想要做的最简单的方法是将您的 ListView 定义为 SelectionMode="Single" 并将 SelectedItem 属性绑定到您的 ViewModel 的相应属性。要阻止任何手动交互,只需在其上放置一个带有 IsHittestVisible="True" 的 Grid 以阻止任何手动交互。如下所示:
    <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 在突出显示版本和普通版本之间切换模板/样式。
    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,您甚至可以通过不同的模板实现符号、图像等。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-11-30
      • 1970-01-01
      • 2010-09-26
      • 1970-01-01
      • 1970-01-01
      • 2015-05-18
      • 1970-01-01
      • 2012-08-10
      相关资源
      最近更新 更多