我有一个应用程序,用于在高架投影仪上显示歌曲.目前编写的方式是使用文本框的堆栈面板,每个文本框的每一行都显示.还可以选择在每条线上方显示和弦.
我面临的问题是人们经常想要为歌曲文本和和弦文本制作更小或更大的字体.每次更改时,都必须编辑歌曲以再次排列和弦.文本的对齐也会影响和弦的位置.
我正在寻找一种更健壮的方法来将一个和弦与一段文本对齐,并将它保持在相对于它的单词的相同位置.我曾想过使用画布,但不知道如何用正确的单词排列文本.
对于什么最适合这种情况,我有点不知所措,并希望得到任何建议.
最佳答案 我认为将Chord和Txt Char一起引用是一个好主意.一个StackPanel可以容纳2个TextBlocks.从那里它只是向外思考.
每一行都可以是一个ItemsControl水平堆叠这些StackPanels.
然后,常规ListBox可以保存这些行.
ViewModels.cs
using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Runtime.CompilerServices;
namespace Karaoke
{
public class ChordData
{
public ChordData(string chord, int position)
{
Chord = chord;
Position = position;
}
#region Chord Property
private String _chord;
public String Chord
{
get { return _chord; }
set { if (value != _chord) _chord = value; }
}
#endregion Chord Property
#region Position Property
private int _position;
public int Position
{
get { return _position; }
set { if (value != _position) _position = value; }
}
#endregion Position Property
}
public class KaraokeChar
{
public KaraokeChar(char txt)
{
Txt = txt;
Chord = "";
}
#region Txt Property
private Char _txt;
public Char Txt
{
get { return _txt; }
set { if (value != _txt) _txt = value; }
}
#endregion Txt Property
#region Chord Property
private String _chord;
public String Chord
{
get { return _chord; }
set { if (value != _chord) _chord = value; }
}
#endregion Chord Property
}
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] String propName = null)
{
// C#6.O
// PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
if (PropertyChanged != null)
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propName));
}
}
public class ItemViewModel : ViewModelBase
{
public ItemViewModel(string txt, List<ChordData> chordList)
{
foreach (char c in txt)
{
Line.Add(new KaraokeChar(c));
}
foreach (ChordData chord in chordList)
{
Line[chord.Position].Chord = chord.Chord;
}
}
#region Line Property
private ObservableCollection<KaraokeChar> _line = new ObservableCollection<KaraokeChar>();
public ObservableCollection<KaraokeChar> Line
{
get { return _line; }
set
{
if (value != _line)
{
_line = value;
OnPropertyChanged();
}
}
}
#endregion Line Property
}
public class MainViewModel : ViewModelBase
{
#region Song Property
private ObservableCollection<ItemViewModel> _song = new ObservableCollection<ItemViewModel>();
public ObservableCollection<ItemViewModel> Song
{
get { return _song; }
set
{
if (value != _song)
{
_song = value;
OnPropertyChanged();
}
}
}
#endregion Song Property
#region TextFont Property
private int _textFont;
public int TextFont
{
get { return _textFont; }
set
{
if (value != _textFont)
{
_textFont = value;
OnPropertyChanged();
}
}
}
#endregion TextFont Property
#region ChordFont Property
private int _chordFont;
public int ChordFont
{
get { return _chordFont; }
set
{
if (value != _chordFont)
{
_chordFont = value;
OnPropertyChanged();
}
}
}
#endregion ChordFont Property
}
}
MainWindow.xaml.cs
using System;
using System.IO;
using System.Linq;
using System.Windows;
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace Karaoke
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
ViewModel.TextFont = 25;
ViewModel.ChordFont = 20;
SongData();
}
private void SongData()
{
ObservableCollection<ItemViewModel> Song = new ObservableCollection<ItemViewModel>();
Song.Add(new ItemViewModel("The dog and the cat",
new List<ChordData>() { new ChordData("D", 0) }));
Song.Add(new ItemViewModel("They take up the middle",
new List<ChordData>()));
Song.Add(new ItemViewModel("Where the honey bee hums",
new List<ChordData>() { new ChordData("A", 8) }));
Song.Add(new ItemViewModel("And Coyote howls",
new List<ChordData>() { new ChordData("A", 2), new ChordData("D", 9) }));
ViewModel.Song = Song;
}
// C#6.O
// public MainViewModel ViewModel => (MainViewModel)DataContext;
public MainViewModel ViewModel
{
get { return (MainViewModel)DataContext; }
}
}
}
MainWindow.xaml
<Window x:Class="Karaoke.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Karaoke"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:MainViewModel />
</Window.DataContext>
<StackPanel Background="Black">
<Label Foreground="Yellow" FontSize="{Binding TextFont}" HorizontalAlignment="Center">All God's Critters</Label>
<ListBox ItemsSource="{Binding Song}"
Background="Transparent"
BorderBrush="Transparent"
Margin="40,0">
<ListBox.ItemTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding Line}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Chord}" FontSize="{Binding DataContext.ChordFont, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" Foreground="Purple"/>
<TextBlock Text="{Binding Txt}" FontSize="{Binding DataContext.TextFont, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" Foreground="White"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</Window>
更改字体大小就像更改ViewModel道具一样简单: