【问题标题】:Change the Foreground color of a TextBlock inside a ListView's DataTemplate when the item is selected选择项目时更改 ListView DataTemplate 中 TextBlock 的前景色
【发布时间】:2013-12-21 04:01:41
【问题描述】:

我正在使用 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>

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

【问题讨论】:

    标签: xaml windows-8 winrt-xaml windows-8.1 winrt-xaml-toolkit


    【解决方案1】:

    这可以满足您的要求。

    使用此 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 更新列表的内容是最简单和最轻量级的方法。在这种情况下,我正在更新绑定到椭圆的颜色。但是,如果这是一组复杂的更改,我可能只是设置一个样式。另一种选择是在模板中隐藏和显示一整套控件。但是,您不能更改数据模板,因为在重新绘制网格之前不会重新渲染它,这不是您想要做的。

    就像更改 Ellipse 颜色一样,您可以更改 TextBlock Foreground 就像您在问题中提出的那样。无论哪种方式,这都会以最优雅的方式为您提供您想要的。

    祝你好运!

    【讨论】:

    • 非常感谢您的提示;感谢您花时间解释这一点。
    【解决方案2】:

    您可以简单地处理ListView 上的SelectionChanged 事件,并通过更改绑定到@ 的SelectedItem 上的视图模型值来更改先前选择的项目和新选择的项目的Foreground 987654328@.

    您还可以使用ListView.ItemContainerGenerator.ContainerFromItem(ListView.SelectedItem) + VisualTreeHelper 找到TextBlock,如Jerry Nixon's blog post 并直接更改前台,但如果您的ListView 是虚拟化的(默认情况下),该技术会出现问题,因为如果您从所选项目滚动并返回 - 更改了 Foreground 的项目视图可能会被回收并用于您收藏中的另一个项目。

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

    【讨论】:

    • 我已经设法使用带有 SelectedForeground 的 TextBlock 来做到这一点。但是如何在选择项目时将数据板内部椭圆的填充属性设置为SelectorGeGoroundge?源代码在这里:kris.blob.core.windows.net/public/ListViewProblem.zip 可能无法使用纯 XAML 并需要代码隐藏?
    • 您可以尝试将Ellipse 的Fill 绑定到...其父级的Foreground 或TextBlock?不太确定...您也可以将椭圆放入 ItemContainerStyle 并在视觉状态更改上应用颜色更改。
    猜你喜欢
    • 2018-09-01
    • 1970-01-01
    • 2014-02-26
    • 2010-12-12
    • 2013-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-03
    相关资源
    最近更新 更多