简体   繁体   English

WPF-显示具有不同颜色的TextBlock

[英]WPF - Display TextBlock with different colors

so what am trying to do is to display a TextBlock, using a different color for each line, and ideally I would like to use binding. 因此,我们要做的是显示一个TextBlock,每行使用不同的颜色,理想情况下,我想使用绑定。

My TextBlock may display a list of Items, each Item has Texte and Color property. 我的TextBlock可能显示项目列表,每个项目都有Texte和Color属性。 With a foreach, I want to display one line per item, with the Texte property, in specified Color. 对于foreach,我想使用Texte属性以指定的颜色显示每个项目一行。

I already tried the following : 我已经尝试了以下方法:

1)I make a TextBlock, whose Text is binded to a string property in ViewModel, and with a foreach I just fill the string, but in that case cannot apply the colors on each line as I want. 1)我制作了一个TextBlock,其Text绑定到ViewModel中的字符串属性,并且使用foreach我只是填充字符串,但是在那种情况下,不能按我希望的那样在每行上应用颜色。

2)I found that link on stack that helped a bit, where it is advised to use the Run . 2)我发现堆栈上的链接有所帮助,建议在其中使用Run

So in my ViewModel I fill the TextBlock like that : 所以在我的ViewModel中,我像这样填充TextBlock:

private TextBlock legende;
public TextBlock Legende
{
   get { return legende; }
   set
   {
     legende = value;
     this.NotifyPropertyChanged("Legende");
   }
}
public void UpdateLegend(Legend legende)
{
    this.Legende = new TextBlock();
    this.Legende.TextWrapping = TextWrapping.Wrap;
    this.Legende.Margin = new Thickness(10);
    this.Legende.FontSize = 14;
    this.Legende.LineStackingStrategy=LineStackingStrategy.BlockLineHeight;
    this.Legende.LineHeight = 20;
    int i = 0;
    foreach(LegendItem item in legende.list)
    {
      if(i==0)
      {
        Run run = new Run(item.Texte);
        run.Foreground = item.Color;
        this.Legende.Inlines.Add(run);
      }
      else
      {
         Run run = new Run(")\r\n"+item.Texte);
         run.Foreground = item.Color;
         this.Legende.Inlines.Add(run);
      }

      i++;
    }
}

My Model does the following, each time I need to update Legend I do : 每当我需要更新图例时,我的模型都会执行以下操作:

contexte.UpdateLegend(MonGraphe.Legende);
this.CanvasLegend = contexte.Legende;

Then my View : 然后我的看法:

<Grid Grid.Column="2" Background="WhiteSmoke">
    <TextBlock x:Name="CanvasLegend" TextAlignment="Left" HorizontalAlignment="Left"/>
</Grid>

For now it is not working at all and I cannot find why. 现在它根本不起作用,我找不到原因。 I also would like to do everything in my ViewModel, but for that I would need to bind my Textlock to a TextBlock defined in my ViewModel, but cannot find how to do that? 我也想在ViewModel中做所有事情,但是为此,我需要将Textlock绑定到ViewModel中定义的TextBlock,但是找不到该怎么做?

EDIT : 编辑:

As explained by Icebat I am using converter as the following : 如Icebat所述,我正在使用以下转换器:

XML identical to IceBat XML与IceBat相同

ViewModel : ViewModel:

public class ColoringConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            //is your collection IEnumerable<>? If not, adjust as needed
            var legende = value as Legend;
            if (legende == null) return value;

            return legende.list.Select(i => new Run() { Text = i.Texte, Foreground = i.Color }).ToArray();
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
    class ViewModelMainWindow : INotifyPropertyChanged
    {
        private Legend legende;
        public Legend Legende
        {
            get { return legende; }
            set
            {
                legende = value;
                this.NotifyPropertyChanged("Legende");
            }
        }
}

Also include my "Legende" class, as I think this is where there is missunderstanding : 还包括我的“传奇”课程,因为我认为这是一个令人误解的地方:

public class LegendItem 
    {
        public int Type { get; set; }
        public double Diametre { get; set; }
        public double Longueur { get; set; }
        public double Profondeur { get; set; }
        public string Texte { get; set; }
        public Brush Color { get; set; }
        public LegendItem()
        {

        }
    }
    public class Legend : INotifyPropertyChanged
    {
        private ObservableCollection<LegendItem> liste;
        public ObservableCollection<LegendItem> Liste
        {
            get { return liste; }
            set
            {
                liste=value;
                NotifyPropertyChanged(ref liste, value);
            }
        }
        public Legend()
        {
            this.list = new ObservableCollection<LegendItem>();
        }
        public event PropertyChangedEventHandler PropertyChanged;

        public void NotifyPropertyChanged(string propName)
        {
            if (this.PropertyChanged != null)
                this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }
        private bool NotifyPropertyChanged<T>(ref T variable, T valeur, [CallerMemberName] string nomPropriete = null)
        {
            if (object.Equals(variable, valeur)) return false;

            variable = valeur;
            NotifyPropertyChanged(nomPropriete);
            return true;
        }
        public Legend(Repere rep)
        {
            List < Brush >  listColors = new List<Brush>();
            listColors.Add(Brushes.Red);
            listColors.Add(Brushes.MediumBlue);
            listColors.Add(Brushes.Purple);
            listColors.Add(Brushes.LimeGreen);
            listColors.Add(Brushes.DarkOrange);
            listColors.Add(Brushes.Navy);
            listColors.Add(Brushes.DarkRed);
            listColors.Add(Brushes.Chartreuse);
            listColors.Add(Brushes.DodgerBlue);
            listColors.Add(Brushes.Tomato);

            this.list = new ObservableCollection<LegendItem>();
            List<Percage> listPer = rep.liste_percages;
            List<GroupePercage> listeGp = rep.listeGpPercages;


            foreach (Percage per in listPer)
            {
                LegendItem itemExists = this.list.FirstOrDefault(x => x.Type == per.Type && x.Diametre == per.Diametre && x.Profondeur == per.Depth&&x.Longueur==per.Longueur);
                if (itemExists == null)
                {
                    LegendItem newItem = new LegendItem();

                    newItem.Type = per.Type;
                    switch (newItem.Type)
                    {
                        case 51: newItem.Texte = "DRILL "; break;
                        case 58: newItem.Texte = "CounterSink "; break;
                        case 59: newItem.Texte = "Tapping "; break;
                        case 12: newItem.Texte = "Slot "; break;
                        default: newItem.Texte = "NOT FOUND "; break;
                    }
                    newItem.Diametre = per.Diametre;
                    newItem.Longueur = per.Longueur;
                    newItem.Texte += newItem.Diametre.ToString();
                    if (newItem.Type==12)
                    {
                        newItem.Texte = newItem.Diametre + " x " + newItem.Longueur;
                    }
                    newItem.Profondeur = per.Depth;
                    this.list.Add(newItem);
                }
            }
            foreach (GroupePercage per in listeGp)
            {
                LegendItem itemExists = this.list.FirstOrDefault(x => x.Type == per.Type && x.Diametre == per.Diametre && x.Profondeur == per.Depth && x.Longueur == per.Longueur);
                if (itemExists == null)
                {
                    LegendItem newItem = new LegendItem();
                    newItem.Type = per.Type;
                    switch (newItem.Type)
                    {
                        case 51: newItem.Texte = "DRILL "; break;
                        case 58: newItem.Texte = "CounterSink "; break;
                        case 59: newItem.Texte = "Tapping "; break;
                        case 12: newItem.Texte = "Slot "; break;
                        default: newItem.Texte = "NOT FOUND "; break;
                    }
                    newItem.Diametre = per.Diametre;
                    newItem.Longueur = per.Longueur;
                    newItem.Texte += newItem.Diametre.ToString();
                    if (newItem.Type == 12)
                    {
                        newItem.Texte = newItem.Diametre + "x" + newItem.Longueur;
                    }
                    newItem.Profondeur = per.Depth;
                    this.list.Add(newItem);
                }
            }
            for(int i=0;i<this.list.Count();i++)
            {
                this.list[i].Color = listColors[Math.Min(i,9)];
            }
        }
    }

Well, the approach with Runs seems to be the simplest one. 好吧,Runs的方法似乎是最简单的方法。 Not sure where you went wrong, but it all should be relatively easy. 不知道哪里出了问题,但这应该相对容易。 You can just use ItemsControl for inlines: 您可以仅将ItemsControl用于内联:

<TextBlock x:Name="CanvasLegend" TextAlignment="Left" HorizontalAlignment="Left">
    <TextBlock.Inlines>
        <ItemsControl ItemsSource="{Binding LegendItems, ElementName=me, 
                                    Converter={StaticResource coloringConverter}}" />
    </TextBlock.Inlines>
</TextBlock>

I use ElementName to point to the host Window here for simplicity, but you can bind it to your ViewModel. 为了简单起见,我使用ElementName指向宿主窗口,但是您可以将其绑定到ViewModel。 The converter looks like this: 转换器看起来像这样:

public class ColoringConverter : IValueConverter
{
  public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
  {
     //is your collection IEnumerable<>? If not, adjust as needed
     var legend = value as IEnumerable<LegendItem>;
     if (legend == null) return value;

     return legend.Select(i => new Run() { Text = i.Text, Foreground = i.Color }).ToArray();
  }

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

Then just add the converter in the resources somewhere (in my example it's Window): 然后只需将转换器添加到资源中的某个位置(在我的示例中是Window):

<Window.Resources>
    <local:ColoringConverter x:Key="coloringConverter" />
</Window.Resources>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM