【问题标题】:ListView string partially font coloredListView 字符串部分字体颜色
【发布时间】:2019-02-14 07:14:17
【问题描述】:

我有一个这样的 ListView:

 <ListView  Name="myLV"  ItemsSource="{Binding myObservableCollection}" IsSynchronizedWithCurrentItem="True" >
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="v1" Width="150">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <TextBlock Text="{Binding var1}"/>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>
                    <GridViewColumn Header="v2" Width="150">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <TextBlock Text="{Binding var2}"/>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>
                    <GridViewColumn Header="v3" Width="150">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <TextBlock Text="{Binding var3}"/>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>
                </GridView>
            </ListView.View>
        </ListView>

每一行都有一组三个字符串,例如:

  • 字符串 1:aa-bbbb-cc
  • 字符串 2:ax-bbbb-cd
  • 字符串 3:aa-bbbb-ce

现在我想在三个字符串不同的位置部分使用单独的文本颜色。在上面的示例中,我必须为三个字符串中的每一个的第二个和第十个位置着色。

我不知道如何开始这项任务,因为我很难用谷歌搜索这个问题。有什么想法吗?

【问题讨论】:

  • 您可以将文本框拆分为多个运行 () 并使用数据触发器来实现这一目标
  • @DenisSchaf 使用此解决方案,我必须将 标签静态设置为 XAML?但是我不知道我的琴弦有多少位置需要上色?也许是零,也许是 5 或完全
  • mhh...事实上,您想单独查看每个角色,在我看来,如您所说,在运行中单独显示它们是有意义的。此外,如果您的模板包含的运行次数多于字符串中的字符数,它不会受到伤害,因为它们将包含一个空字符串并且是不可见的
  • @DenisSchaf 这意味着,如果我想支持每个字符串的最大长度为 20 个字符,我将不得不在彼此之后设置 20 个 标签。这听起来不太聪明,是吗?
  • 而不是将文本框绑定到字符串,您可以将其绑定到可观察的运行集合,这将使代码看起来更好,并让您有机会在代码中而不是 XAML 中管理运行颜色

标签: c# wpf listview colors


【解决方案1】:

您可以创建一个用户控件,将文本分成四个部分,并允许您独立设置它们的样式。以下示例控件将 Text 作为输入并将部分存储在专用属性中:

public partial class MyFormattedTextControl : UserControl, INotifyPropertyChanged
{
    public MyFormattedTextControl()
    {
        InitializeComponent();
        stack.DataContext = this;
    }

    public string Text
    {
        get { return (string)GetValue(TextProperty); }
        set { SetValue(TextProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Text.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty TextProperty =
        DependencyProperty.Register("Text", typeof(string), typeof(MyFormattedTextControl), new PropertyMetadata(null, OnTextPropertyChanged));

    private static void OnTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var ctrl = (MyFormattedTextControl)d;
        var t = (string)e.NewValue;
        var regex = new Regex("(?<Part1>.)(?<Part2>.)(?<Part3>.{7})(?<Part4>.)");
        var m = regex.Match(t);
        if (!m.Success)
        {
            ctrl.Part1 = ctrl.Part2 = ctrl.Part3 = ctrl.Part4 = string.Empty;
        }
        else
        {
            ctrl.Part1 = m.Groups["Part1"].Value;
            ctrl.Part2 = m.Groups["Part2"].Value;
            ctrl.Part3 = m.Groups["Part3"].Value;
            ctrl.Part4 = m.Groups["Part4"].Value;
        }
    }

    private string part1;

    public string Part1
    {
        get { return part1; }
        set { part1 = value; OnPropertyChanged(); }
    }

    private string part2;

    public string Part2
    {
        get { return part2; }
        set { part2 = value; OnPropertyChanged(); }
    }


    private string part3;

    public string Part3
    {
        get { return part3; }
        set { part3 = value; OnPropertyChanged(); }
    }

    private string part4;

    public string Part4
    {
        get { return part4; }
        set { part4 = value; OnPropertyChanged(); }
    }

    private void OnPropertyChanged([CallerMemberName] string callerMember = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(callerMember));
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

在 XAML 文件中,用户控件在单独的文本块中显示部分,您可以独立设置样式:

<StackPanel x:Name="stack" Orientation="Horizontal">
    <TextBlock Text="{Binding Part1}" />
    <TextBlock Text="{Binding Part2}" Foreground="Red" />
    <TextBlock Text="{Binding Part3}" />
    <TextBlock Text="{Binding Part4}" Foreground="Green" />
</StackPanel>

在您的 ListView 中,您使用用户控件而不是 TextBlock:

<DataTemplate>
  <local:MyFormattedTextControl Text="{Binding var1}" />
</DataTemplate>

更新:根据数据值格式化块

为了给模式提供行值,你可以向用户控件添加另一个依赖属性:

public IEnumerable<bool> PartFlags
{
    get { return (bool[])GetValue(PartFlagsProperty); }
    set { SetValue(PartFlagsProperty, value); }
}

// Using a DependencyProperty as the backing store for PartFlags.  This enables animation, styling, binding, etc...
public static readonly DependencyProperty PartFlagsProperty =
    DependencyProperty.Register("PartFlags", typeof(bool[]), typeof(MyFormattedTextControl), new PropertyMetadata(new bool[] { false, false, false, false }));

为了将布尔值转换为颜色,您可以创建自定义值转换器,例如

public class PartColorValueConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var b = value as bool[] ?? new bool[] { };
        var i = System.Convert.ToInt32(parameter);
        return b.ElementAtOrDefault(i) ? Brushes.Red : Brushes.Black;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

您可以在用户控件中使用此转换器将颜色应用于部件:

<UserControl x:Class="MyWpfApp.MyFormattedTextControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:MyWpfApp"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <UserControl.Resources>
        <local:PartColorValueConverter x:Key="partColorValueConv" />
    </UserControl.Resources>
    <StackPanel x:Name="stack" Orientation="Horizontal">
        <TextBlock Text="{Binding Part1}" Foreground="{Binding PartFlags, Converter = {StaticResource partColorValueConv}, ConverterParameter=0}" />
        <TextBlock Text="{Binding Part2}" Foreground="{Binding PartFlags, Converter = {StaticResource partColorValueConv}, ConverterParameter=1}" />
        <TextBlock Text="{Binding Part3}" Foreground="{Binding PartFlags, Converter = {StaticResource partColorValueConv}, ConverterParameter=2}" />
        <TextBlock Text="{Binding Part4}" Foreground="{Binding PartFlags, Converter = {StaticResource partColorValueConv}, ConverterParameter=3}" />
    </StackPanel>
</UserControl>

为了测试,我在包含模式的元组中添加了第四个值(在我的例子中,是一个随机生成的模式):

<local:MyFormattedTextControl Text="{Binding Item1}" PartFlags="{Binding Item4}" />

【讨论】:

  • 如果我可以告诉 MyFormattedTextControl,字符串的哪些部分需要着色,这个解决方案会很有用。是否可以另外向 var1 传递一个类似 int[1,0,0,1,1] 的数组,表示红色、黑色、黑色、红色、红色。该数组将是与 var1 相同的实例的成员
  • @JulianHerbel 有几种方法可以实现这一点。如果你有一个共同的逻辑,比如“每个都是红色的,其他都是黑色的”,你可以扩展控制并在那里实现逻辑。否则,您可以将另一个依赖属性添加到获取该数组的控件并将其绑定到该行的相应数组。
  • 这就是重点。我不知道如何正确扩展您的类,以便为我的数组 int[] 拥有第二个依赖属性,我玩了一段时间,但我无法访问该数组。能给个提示吗?
  • @Julian 我已经用示例更新了答案。希望这个帮手。
猜你喜欢
  • 1970-01-01
  • 2015-02-25
  • 1970-01-01
  • 1970-01-01
  • 2013-10-26
  • 2019-02-18
  • 2015-01-12
  • 2013-07-20
  • 1970-01-01
相关资源
最近更新 更多