У меня проблема со списком, который должен учитывать разные цвета в его Элементах.
<ListBox i:Name="listBox1" ItemsSource="{Binding MyItems_listbox1}"
IsSynchronizedWithCurrentItem="True">
Теперь я хочу добавить элемент в список, если строка написана разными цветами, например:
listBox1.Items.Add("hallo my name");
Я хочу, чтобы в "список" и отобразилось "hallo" (синее) "мое" (красное) "имя" (зеленое). Есть ли какой-то возможный способ реализовать это?
Чтобы выделить какое-то слово, обычно мы можем думать о управлении RichTextBox
. Однако это не легкий контроль веса. Ему повезло, что WPF поддерживает множество элементов управления (особенно связанных с Document
), что позволяет нам отображать богатый текст. Для облегченного решения вы должны просто использовать TextBlock
представляющий контент для каждого ListViewItem
но мы можем использовать элементы Run
внутри каждого TextBlock
чтобы выделить слова. Во-первых, нам нужно использовать DataTemplate
для установки ItemTemplate
для каждого ListViewItem
. Мы должны использовать Binding
для привязки содержимого строки (каждого элемента) к TextBlock
внутри DataTemplate
. Использование Binding
позволяет нам вводить какой-то пользовательский код в Converter
. Вот код детали:
Код позади:
//The main window class
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
//Init the Keywords first
Keywords.Add("hallo", Brushes.Blue);
Keywords.Add("my", Brushes.Red);
Keywords.Add("name", Brushes.Green);
//Add some items to the ListView
lv.Items.Add("hallo my name");
lv.Items.Add("hello my name");
lv.Items.Add("goodbye your name");
}
//This dictionary used to hold your keywords corresponding to their Brush
public static Dictionary<string, Brush> Keywords = new Dictionary<string,Brush>();
}
//The converter class
public class InlinesConverter : IValueConverter
{
object IValueConverter.Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var content = Convert.ToString(value);
var dict = MainWindow.Keywords;
var outString = "<TextBlock xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" xml:space=\"preserve\">";
foreach(var word in content.Split(' ')){
var converted = word;
Brush fg;
if (dict.TryGetValue(word, out fg)) {
var run = new Run(word);
run.Foreground = fg;
converted = System.Windows.Markup.XamlWriter.Save(run);
}
outString += converted + " ";
}
outString += "</TextBlock>";
return System.Windows.Markup.XamlReader.Parse(outString);
}
object IValueConverter.ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
XAML:
<Window x:Class="WpfApplication.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="SO3" Height="300" Width="300"
xmlns:local="clr-namespace:WpfApplication"
>
<Window.Resources>
<local:InlinesConverter x:Key="inlinesConverter"/>
</Window.Resources>
<Grid>
<ListView Name="lv">
<ListView.ItemTemplate>
<DataTemplate>
<ContentControl FontSize="20">
<Binding Converter="{StaticResource inlinesConverter}"/>
</ContentControl>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Window>
Обратите внимание на пространство имен здесь, в этой демонстрации я использовал пространство имен по умолчанию WpfApplication
. Если у вас другое, вы должны отредактировать его внутри кода XAML. Также обратите внимание, что ItemTemplate
игнорируется, если вы добавляете элементы прямо в код XAML. Мы должны использовать код, расположенный либо через Items.Add
либо привязку данных (с помощью ItemsSource
).
Вероятным способом добиться этого может быть использование ListBox DataTemplate
где вы будете отправлять строку в виде массива, а затем внутри DataTemplate
вы можете иметь другой TextBlock для всех частей строки
<TextBlock Text="hallo " Foreground="Blue" />
<TextBlock Text="my" Foreground="Red" />
<TextBlock Text=" name" Foreground="Green" />