选择项目时更改 ListView 的 DataTemplate 内 TextBlock 的前景色

问题描述 投票:0回答:3

我正在使用 C#/XAML 构建 Windows 应用商店应用程序。

我有一个绑定到 ItemsSource 的简单 ListView。有一个 DataTemplate,它定义了每个项目的结构,并且其中有一个 ContentControl 和一个 TextBlock。

我希望在选择该项目时更改 TextBlock 的前景色。有谁知道我该怎么做?

<ListView Grid.Column="1" 
              ItemsSource="{Binding Categories}" 
              ItemContainerStyle="{StaticResource CategoryListViewItemStyle}"
              Background="{StaticResource DeepRedBrush}">
        <ListView.ItemTemplate>
            <DataTemplate>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition/>
                        <ColumnDefinition/>
                    </Grid.ColumnDefinitions>
                    <ContentControl Content="{Binding Id, Converter={StaticResource Cat2Icon}}" HorizontalAlignment="Left" VerticalAlignment="Center" Width="110" Foreground="#FF29BCD6"/>
                    <TextBlock x:Name="catName" HorizontalAlignment="Left" Margin="0" TextWrapping="Wrap" Text="{Binding Name}" Grid.Column="1" VerticalAlignment="Center" FontSize="18.667" 
                               Foreground="White"/>

                </Grid>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

目前它设置为“白色”,所以我需要的只是一些绑定表达式,它将根据列表视图中项目的选定状态更改前景属性。

xaml windows-8 winrt-xaml windows-8.1 winrt-xaml-toolkit
3个回答
2
投票

这符合您的要求。

使用此 XAML

<Grid x:Name="LayoutRoot" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <ListView x:Name="MyListView" ItemsSource="{Binding Items}" SelectionMode="Single" SelectedItem="{Binding Selected, Mode=TwoWay}">
        <ListView.ItemTemplate>
            <DataTemplate>
                <Grid Height="100" Width="300">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="100" />
                        <ColumnDefinition />
                    </Grid.ColumnDefinitions>
                    <Ellipse x:Name="ellipse">
                        <Ellipse.Fill>
                            <SolidColorBrush Color="{Binding Color}" />
                        </Ellipse.Fill>
                    </Ellipse>
                    <TextBlock Grid.Column="1" VerticalAlignment="Center" Margin="10" Text="{Binding Title}" Style="{StaticResource HeaderTextBlockStyle}" />
                </Grid>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</Grid>

背后的代码:

public class MyModel : BindableBase
{
    string _Title = default(string);
    public string Title { get { return _Title; } set { SetProperty(ref _Title, value); } }

    Color _Color = Colors.White;
    public Color Color { get { return _Color; } set { SetProperty(ref _Color, value); } }
}

public class MyViewModel : BindableBase
{
    public MyViewModel()
    {
        var items = Enumerable.Range(1, 10)
            .Select(x => new MyModel { Title = "Title " + x.ToString() });
        foreach (var item in items)
            this.Items.Add(item);
    }

    MyModel _Selected = default(MyModel);
    public MyModel Selected
    {
        get { return _Selected; }
        set
        {
            if (this.Selected != null)
                this.Selected.Color = Colors.White;
            SetProperty(ref _Selected, value);
            value.Color = Colors.Red;
        }
    }

    ObservableCollection<MyModel> _Items = new ObservableCollection<MyModel>();
    public ObservableCollection<MyModel> Items { get { return _Items; } }
}

public abstract class BindableBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected void SetProperty<T>(ref T storage, T value, [System.Runtime.CompilerServices.CallerMemberName] String propertyName = null)
    {
        if (!object.Equals(storage, value))
        {
            storage = value;
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    protected void RaisePropertyChanged([System.Runtime.CompilerServices.CallerMemberName] String propertyName = null)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

它将为您更新您的数据模板。

我想快速指出这一点:通过 ViewModel 更新列表内容是最简单、最轻量级的方法。在本例中,我正在更新绑定到椭圆的颜色。但是,如果这是一组复杂的更改,我可能只是设置一种样式。另一种选择是隐藏和显示模板中的整套控件。但是,您无法更改数据模板,因为在网格重新绘制之前它不会重新渲染,而这不是您想要做的。

就像更改椭圆颜色一样,您可以像您在问题中询问的那样更改 TextBlock 前景。不管怎样,这都会以最优雅的方式让你得到你想要的。

祝你好运!


1
投票

您可以简单地处理

SelectionChanged
上的
ListView
事件,并通过更改绑定到
Foreground
SelectedItem
上的视图模型值来更改先前选定的项目和新选定项目的
Foreground
.

您还可以使用

TextBlock
+
ListView.ItemContainerGenerator.ContainerFromItem(ListView.SelectedItem)
找到
VisualTreeHelper
,如 Jerry Nixon 的博客文章 中所示,并直接更改前景,但如果您的
ListView
是虚拟化的(默认情况下是虚拟化的),则该技术会出现问题),因为如果您滚动离开所选项目并返回 - 更改后的项目视图
Foreground
可能会被回收并用于集合中的另一个项目。

另一个选项是将

Foreground
绑定到父级
IsSelected
ListViewItem
属性,您也可以通过多种方式执行此操作。例如,您可以将整个
DataTemplate
放入
UserControl
中,并将
Foreground
绑定到该控件的
Parent
。问题是我认为
Parent
不是依赖属性,并且我在
ParentChanged
上看不到
FrameworkElement
事件(定义
UserControl
属性的
Parent
的基类),因此走这条路可能很困难。绑定它们的另一种方法是定义一个附加的依赖属性或行为来为您设置该绑定,但这很复杂(尽管我已经创建了一个您可以使用的here)。

最后您可以修改

ListView.ItemContainerStyle
并更改
SelectedBackground
值。如果可行 - 这将是理想的解决方案。

    <Style TargetType="ListViewItem">
        <Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}"/>
        <Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}"/>
        <Setter Property="Background" Value="Transparent"/>
        <Setter Property="TabNavigation" Value="Local"/>
        <Setter Property="IsHoldingEnabled" Value="True"/>
        <Setter Property="Margin" Value="0,0,18,2"/>
        <Setter Property="HorizontalContentAlignment" Value="Left"/>
        <Setter Property="VerticalContentAlignment" Value="Top"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="ListViewItem">
                    <ListViewItemPresenter CheckHintBrush="{ThemeResource ListViewItemCheckHintThemeBrush}" CheckBrush="{ThemeResource ListViewItemCheckThemeBrush}" ContentMargin="4" ContentTransitions="{TemplateBinding ContentTransitions}" CheckSelectingBrush="{ThemeResource ListViewItemCheckSelectingThemeBrush}" DragForeground="{ThemeResource ListViewItemDragForegroundThemeBrush}" DragOpacity="{ThemeResource ListViewItemDragThemeOpacity}" DragBackground="{ThemeResource ListViewItemDragBackgroundThemeBrush}" DisabledOpacity="{ThemeResource ListViewItemDisabledThemeOpacity}" FocusBorderBrush="{ThemeResource ListViewItemFocusBorderThemeBrush}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" Padding="{TemplateBinding Padding}" PointerOverBackgroundMargin="1" PlaceholderBackground="{ThemeResource ListViewItemPlaceholderBackgroundThemeBrush}" PointerOverBackground="{ThemeResource ListViewItemPointerOverBackgroundThemeBrush}" ReorderHintOffset="{ThemeResource ListViewItemReorderHintThemeOffset}" SelectedPointerOverBorderBrush="{ThemeResource ListViewItemSelectedPointerOverBorderThemeBrush}" SelectionCheckMarkVisualEnabled="True" SelectedForeground="{ThemeResource ListViewItemSelectedForegroundThemeBrush}" SelectedPointerOverBackground="{ThemeResource ListViewItemSelectedPointerOverBackgroundThemeBrush}" SelectedBorderThickness="{ThemeResource ListViewItemCompactSelectedBorderThemeThickness}" SelectedBackground="{ThemeResource ListViewItemSelectedBackgroundThemeBrush}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

0
投票

它对我有用

<TextBlock.Style>
    <Style TargetType="{x:Type TextBlock}">
        <Style.Triggers>
            <DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=ListViewItem}}" Value="True">
                <Setter Property="Foreground" Value="Red" />
            </DataTrigger>
        </Style.Triggers>
    </Style>
</TextBlock.Style>
© www.soinside.com 2019 - 2024. All rights reserved.