为 ComboBox 中的 ItemSource 值添加前缀

Add prefix to ItemSource values in ComboBox

这是我的 app.xaml 文件(删减):

<Application.Resources>
    <x:Array x:Key="SongTitleString" Type="local:ComboBoxItemString">
        <local:ComboBoxItemString ValueString = "Song 1"/>
        <local:ComboBoxItemString ValueString = "Song 2"/>
        <local:ComboBoxItemString ValueString = "Song 3"/>
    </x:Array>
</Application.Resources>

这是class:

namespace OCLMEditor
{
    /// This class provides us with an object to fill a ComboBox with
    /// that can be bound to string fields in the binding object.
    public class ComboBoxItemString
    {
        public string ValueString { get; set; }
    }
}

这是标记:

<ComboBox x:Name="comboSongOpen" ItemsSource="{StaticResource SongTitleString}" 
    DisplayMemberPath="ValueString" 
    SelectedValuePath="ValueString" 
    SelectedValue="{Binding SongTitle}">
    <ComboBox.MaxWidth>
        <Binding Path="ActualWidth" 
            ElementName="textWeeklyBibleReading"/>
    </ComboBox.MaxWidth>
</ComboBox>

一切顺利。这个问题是,当歌曲标题显示在组合上时,我想在歌曲标题前加上一个 3 位数字。例如:

001 - Song 1
002 - Song 2
003 - Song 3

最后,在应用程序的其他地方,我会想使用组合框选择的索引从资源中提取正确的歌曲标题(没有前缀)。

这可能吗?

更新:

如果我创建 XML:

<?xml version="1.0" encoding="utf-8" ?>
<Settings>
  <SongTitles>
    <SongTitle Number="1" Title = "Jehovah's Attributes"/>
  </SongTitles>
</Settings>

并将其作为资源添加到 WPF:

<Window.Resources>
    <XmlDataProvider x:Key="XmlData" Source="OCLM_Resources.xml" XPath="Settings/SongTitles" />
</Window.Resources>

然后使用:

<ComboBox x:Name="comboSongOpen"
           ItemsSource="{Binding Source={StaticResource XmlData}, XPath=./SongTitle}" DisplayMemberPath="@Title">
    <ComboBox.MaxWidth>
        <Binding Path="ActualWidth" 
            ElementName="textWeeklyBibleReading"/>
    </ComboBox.MaxWidth>
</ComboBox>

在drop中显示Title。但是我无法完全理解使用 ItemTemplate and/or stiching 属性(用于格式化 0.000)在一起。

根据我对 OP 的评论,我想这更像是一个建议:

如果将歌曲列表卸载到文件中,则可以在初始化应用程序以创建歌曲列表时读取该文件。文件的实际结构由您决定。通常使用 CSV 文件,因为这是一种分隔值的简单方法(用逗号),但您可以使用任何您喜欢的分隔符。

在这种情况下,鉴于您可以使用 C# 读取文件的一些简单方法,我什至建议您用新行分隔您的歌曲名称。如果您这样做,编制您的歌曲列表将非常简单:

string[] songList = System.IO.File.ReadAllLines(@"songlist.txt");
for (int i = 0; i < songList.Length; i++) {
     string newItem = ((i+1).ToString()) + " " + songList[i];
     combo1.Items.Add(newItem);
}

List<string> songs = new List<string>();
for (int i = 0; i < songList.Length; i++) {
     songs.Add((i + 1).ToString() + " " + songList[i]);
}

combo1.ItemsSource = songs;

因此在这些示例中,组合框的内容将是

1 Song 1

2 Song 2

编辑:根据您 post

的最后一部分

Eventually, elsewhere in the application, I will want to use the combo box selected index to pull out the right song title (with no prefix) from the resources.

在您的示例中,格式为 001 - Song 1

如果您只想要没有前缀的歌曲标题,selectedIndex,您有几个选择。

1) 您可以在应用程序初始化时创建第二个列表,该列表不包含前缀。在编制列表时,制作第二个列表,并添加不带前缀的歌曲名称。然后,您可以使用 ComboBox.

selectedIndex 属性 引用此列表

2) 您可以使用 selectedIndex 属性 然后使用字符串操作的一些变体来提取歌曲名称。

string[] selectedSong = combo1.Items[0].ToString().Split('-');

在此示例中,没有前缀的歌曲名称将在 selectedSong[1] 内。

按照 EdPlunkett 的建议,使用 ComboBox 的 ItemTemplate 参考以下示例。

<Window x:Class="ChkList_Learning.Window2"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:ChkList_Learning"
    mc:Ignorable="d"
    Title="Window2" Height="300" Width="300">
<Grid>
    <StackPanel>
        <ComboBox ItemsSource="{Binding SongList}" x:Name="songsCombo">
            <ComboBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding Title}"></TextBlock>
                        <TextBlock Text=" - "></TextBlock>
                        <TextBlock Text="{Binding SongName}"></TextBlock>
                    </StackPanel>
                </DataTemplate>
            </ComboBox.ItemTemplate>
        </ComboBox>
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="ID"></TextBlock>
            <TextBox Width="100" Text="{Binding ElementName=songsCombo,Path=SelectedItem.Title}"></TextBox>
        </StackPanel>
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="Song Name"></TextBlock>
            <TextBox Width="100"  Text="{Binding ElementName=songsCombo,Path=SelectedItem.SongName}"></TextBox>
        </StackPanel>
    </StackPanel>
</Grid>

    using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace ChkList_Learning
{
    /// <summary>
    /// Interaction logic for Window2.xaml
    /// </summary>
    public partial class Window2 : Window
    {
        public Window2()
        {
            InitializeComponent();
            this.DataContext = new SongViewModel();
        }
    }

    class SongViewModel
    {
        public ObservableCollection<Song> SongList { get; set; }

        public SongViewModel()
        {
            SongList = new ObservableCollection<Song>();
            for (int i = 0; i < 10; i++)
            {
                Song song = new Song();
                song.Title = (i + 1).ToString();
                song.SongName = "Song Name" + (i + 1).ToString();
                song.AlbumName = "My Album";
                SongList.Add(song);
            }
        }
    }

    class Song
    {
        public string Title { get; set; }
        public string SongName { get; set; }

        public string AlbumName { get; set; }
    }
}

这是一个非常简单的纯 xaml 解决方案。您不需要更改任何其他内容。

            //add this to your resource.  Obviously you should put this in code if you have lots of items
            <AlternationConverter x:Key="AlternateForegroundConverter">
                <s:Int16>1</s:Int16>
                <s:Int16>2</s:Int16>
                <s:Int16>3</s:Int16>
                <s:Int16>4</s:Int16>
                <s:Int16>5</s:Int16>
                //more if necessary
            </AlternationConverter>

        <ComboBox x:Name="comboSongOpen" ItemsSource="{StaticResource SongTitleString}" SelectedValuePath="ValueString" SelectedValue="{Binding SongTitle}" AlternationCount="99999" >
            <ComboBox.ItemTemplate>
                <DataTemplate DataType="local:ComboBoxItemString">
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding (ItemsControl.AlternationIndex), RelativeSource={RelativeSource AncestorType=ListBoxItem}, StringFormat='000 - ', Converter={StaticResource AlternateForegroundConverter}}" />
                        <TextBlock Text="{Binding ValueString}" />
                    </StackPanel>
                </DataTemplate>
            </ComboBox.ItemTemplate>
            <ComboBox.MaxWidth>
                <Binding Path="ActualWidth" ElementName="textWeeklyBibleReading"/>
            </ComboBox.MaxWidth>

编辑:需要这个命名空间

xmlns:s="clr-namespace:System;assembly=mscorlib"

编辑:回应更新的问题

将 DataTemplate 更改为(在这种情况下您不需要 AlternationConverter)。

        <ComboBox.ItemTemplate>
            <DataTemplate DataType="local:ComboBoxItemString">
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="{Binding Number, StringFormat='000 - '}" />
                    <TextBlock Text="{Binding ValueString}" />
                </StackPanel>
            </DataTemplate>

//add Number property to you class
public class ComboBoxItemString
{
    public string ValueString { get; set; }
    public int Number { get; set; }
}

//add the array
<x:Array x:Key="SongTitleString" Type="local:ComboBoxItemString">
    <local:ComboBoxItemString ValueString = "Song 1" Number = "1" />
    <local:ComboBoxItemString ValueString = "Song 2" Number = "2" />
    <local:ComboBoxItemString ValueString = "Song 3" Number = "3" />
</x:Array>

但是有一个很大的问题。你列出的是正确的。但是如果你 select 一个项目,ComboBox 也会显示“001 - Jehovah's Attributes”。要让它只显示"Jehovah's Attributes",你需要修改控件模板。

只需添加一个带有前缀

的 DisplayMemberPath
<Application.Resources>
    <x:Array x:Key="SongTitleString" Type="local:ComboBoxItemString">
        <local:ComboBoxItemString ValueString = "Song 1" ValueStringLong = "# 1 Song 1"/>
        <local:ComboBoxItemString ValueString = "Song 2" ValueStringLong = "# 2 Song 1"/>
        <local:ComboBoxItemString ValueString = "Song 3" ValueStringLong = "# 3 Song 1"/>
    </x:Array>
</Application.Resources>

DisplayMemberPath="ValueStringLong"