我有一个用于在高架投影仪上显示歌曲的应用程序。目前编写的方式是使用文本框的堆栈面板,每个文本框的每一行都显示。还可以选择在每条线上方显示和弦。
我面临的问题是人们经常想要为歌曲文本和和弦文本制作更小或更大的字体。每次更改时,都必须编辑歌曲以再次排列和弦。文本的对齐也会影响和弦的位置。
我正在寻找一种更健壮的方法,将和弦与一段文字对齐,并将其保持在与其相关的相同位置。我曾想过使用画布,但不知道如何用正确的单词排列文本。
我对哪种方法最适合这一点感到茫然,并希望得到任何建议。
答案 0 :(得分:1)
我认为将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道具一样简单:
答案 1 :(得分:0)
我这样做的方法是让每个有合唱的单词都在两行文本块中(使用&#34;运行&#34;和&#34; Linebreak&#34;在TextBlock内容中) )。这意味着你必须将你的线条分成没有合唱和线条的线条。
如果一条线有合唱,那么你必须将它分成没有合唱的文本块,然后是带有合唱的文本块,然后是没有合唱的文本块。 (您可以使用具有Horizontanl方向的堆叠面板将它们全部放在同一条线上)
这不是一件简单的事情,但它可以让你拥有你想要的东西。