选择项目时,更改ListView的DataTemplate中TextBlock的前景颜色

时间:2013-12-04 15:24:31

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

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

我有一个简单的ListView绑定到ItemsSource。有一个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属性。

2 个答案:

答案 0 :(得分: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更新列表内容是最简单,最轻量级的方法。在这种情况下,我正在更新绑定到椭圆的颜色。但是,如果这是一组复杂的变化,我可能只会设置一个样式。另一个选项是隐藏和显示模板中的整个控件集。但是,您无法更改数据模板,因为在网格重新绘制之前不会重新渲染数据模板,而这不是您想要执行的操作。

就像更改Ellipse颜色一样,您可以像在问题中一样更改TextBlock Foreground。无论哪种方式,这都能以最优雅的方式为您提供所需的一切。

祝你好运!

答案 1 :(得分:1)

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

您还可以使用Foreground中的TextBlock + ListView.ItemContainerGenerator.ContainerFromItem(ListView.SelectedItem)找到VisualTreeHelper并直接更改前景,但如果ListView该技术存在问题虚拟化(默认情况下),因为如果您从所选项目向外滚动并返回 - 具有更改的Foreground的项目视图可能会被回收并用于您馆藏中的其他项目。

另一种选择是将Foreground绑定到父IsSelected的{​​{1}}属性,您也可以通过多种方式执行该属性。例如,您可以将整个ListViewItem放在DataTemplate中,并将UserControl绑定到该控件的Foreground。问题是我认为Parent不是依赖属性,我在Parent上看不到ParentChanged事件(FrameworkElement的基类定义了UserControl属性) ,所以走这条路可能很难。绑定这些的另一种方法是定义一个附加的依赖属性或行为,为你设置绑定,但这很复杂(虽然我已经创建了一个你可以使用Jerry Nixon's blog post)。

最后,您可以修改Parent并更改ListView.ItemContainerStyle值。如果可行 - 这将是理想的解决方案。

SelectedBackground