C# “如何垂直”;中心“;对齐多行文字

C# “如何垂直”;中心“;对齐多行文字,c#,wpf,user-controls,C#,Wpf,User Controls,对不起,如果标题有点误导,我很难给它命名。它也不完全是“中心”。(更多解释见下文) 嗨,我要做一个项目来写编号的乐谱。但我发现了一个障碍,在平衡“字体”。(请参见下图了解视觉效果) 我需要1234在一条直线上 我使用WrapPanel作为笔记的容器(如屏幕中) 主要问题在于音高点,它位于音符上方或下方。音高绑定到音符,所以我需要在1个用户控件中处理它。但是,如果是这样的话,那么我无法控制注释“字体”的位置在一行中 以下是我的笔记用户控制代码: XAML <UserControl x:Cl

对不起,如果标题有点误导,我很难给它命名。它也不完全是“中心”。(更多解释见下文)

嗨,我要做一个项目来写编号的乐谱。但我发现了一个障碍,在平衡“字体”。(请参见下图了解视觉效果)

  • 我需要
    1234
    在一条直线上
  • 我使用
    WrapPanel
    作为笔记的容器(如屏幕中)
  • 主要问题在于音高点,它位于音符上方或下方。音高绑定到音符,所以我需要在1个用户控件中处理它。但是,如果是这样的话,那么我无法控制注释“字体”的位置在一行中

    以下是我的笔记用户控制代码:

    XAML

    <UserControl x:Class="RevisiConverter.NumericNoteBox"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" Width="{Binding ActualWidth, ElementName=txbNote}" 
             Height="{Binding ActualHeight, ElementName=mainStack}">
    <StackPanel Name="mainStack">
        <StackPanel Name="topStack">
    
        </StackPanel>
        <Canvas Name="canvas" Width="{Binding ActualWidth, ElementName=txbNote}" Height="{Binding ActualHeight, ElementName=txbNote}"
                HorizontalAlignment="Center">            
            <TextBlock Name="txbNote" Text="1" Foreground="Black" FontSize="15"
                       Margin="0,0,0,-3" FontFamily="Courier" Canvas.Top="0" Canvas.Left="0"/>
        </Canvas>
        <StackPanel Name="botStack">
    
        </StackPanel>
    </StackPanel>
    
    
    

    XAML.CS

    public partial class NumericNoteBox : UserControl
    {
        private Note _child;
        private Line _sharp;
    
        public Note Child
        {
            get { return _child; }
            set
            {
                _child = value;
                Update();
            }
        }
    
        public NumericNoteBox()
        {
            InitializeComponent();
    
            _sharp = null;
        }
    
        public void Update()
        {
            txbNote.Text = _child.MainNote.ToString();
    
            if (_sharp != null)
            {
                _sharp.Visibility = Visibility.Hidden;
            }
    
            topStack.Children.Clear();
            botStack.Children.Clear();
    
            if (_child != null)
            {
                if (_child.Pitch > 0)
                {
                    for (int i = 0; i < _child.Pitch; i++)
                    {
                        topStack.Children.Add(new Ellipse());
                        (topStack.Children[topStack.Children.Count - 1] as Ellipse).Width = 3;
                        (topStack.Children[topStack.Children.Count - 1] as Ellipse).Height = 3;
                        (topStack.Children[topStack.Children.Count - 1] as Ellipse).Fill = Brushes.Black;
    
                        if (_child.Accidental != Note.Accidentals.Flat)
                        {
                            (topStack.Children[topStack.Children.Count - 1] as Ellipse).Margin = new Thickness(0, 1, 0, 0);
                        }
                        else
                        {
                            (topStack.Children[topStack.Children.Count - 1] as Ellipse).Margin = new Thickness(8, 1, 0, 0);
                        }
                    }
                }
                else if (_child.Pitch < 0)
                {
                    for (int i = 0; i < Math.Abs(_child.Pitch); i++)
                    {
                        botStack.Children.Add(new Ellipse());
                        (botStack.Children[botStack.Children.Count - 1] as Ellipse).Width = 3;
                        (botStack.Children[botStack.Children.Count - 1] as Ellipse).Height = 3;
                        (botStack.Children[botStack.Children.Count - 1] as Ellipse).Fill = Brushes.Black;
    
                        if (_child.Accidental != Note.Accidentals.Flat)
                        {
                            (botStack.Children[botStack.Children.Count - 1] as Ellipse).Margin = new Thickness(0, 1, 0, 0);
                        }
                        else
                        {
                            (botStack.Children[botStack.Children.Count - 1] as Ellipse).Margin = new Thickness(8, 1, 0, 0);
                        }
                    }
                }
    
                if (_child.Accidental == Note.Accidentals.Flat)
                {
                    txbNote.Text = "b" + _child.MainNote.ToString();
                }
                else if (_child.Accidental == Note.Accidentals.Sharp)
                {
                    if (_sharp == null)
                    {
                        _sharp = new Line();
                        _sharp.X1 = 10;
                        _sharp.Y1 = 2.5;
                        _sharp.X2 = -2.5;
                        _sharp.Y2 = 12.5;
                        _sharp.StrokeThickness = 1;
                        _sharp.Stroke = Brushes.Black;
    
                        canvas.Children.Add(_sharp);
                    }
    
                    _sharp.Visibility = Visibility.Visible;
                }
            }
        }
    }
    
    public分部类NumericNoteBox:UserControl
    {
    私人票据(儿童);;
    私人线路(u sharp),;
    公共票据儿童
    {
    获取{return\u child;}
    设置
    {
    _孩子=价值;
    更新();
    }
    }
    公共数字记事本()
    {
    初始化组件();
    _夏普=零;
    }
    公共无效更新()
    {
    txbNote.Text=_child.MainNote.ToString();
    如果(_sharp!=null)
    {
    _sharp.Visibility=Visibility.Hidden;
    }
    topStack.Children.Clear();
    botStack.Children.Clear();
    如果(_child!=null)
    {
    如果(_child.Pitch>0)
    {
    对于(int i=0;i<\u child.Pitch;i++)
    {
    topStack.Children.Add(新椭圆());
    (topStack.Children[topStack.Children.Count-1]作为椭圆)。宽度=3;
    (topStack.Children[topStack.Children.Count-1]作为椭圆)。高度=3;
    (topStack.Children[topStack.Children.Count-1]为椭圆)。填充=画笔。黑色;
    如果(_child.contractive!=Note.acidentals.Flat)
    {
    (topStack.Children[topStack.Children.Count-1]为椭圆)。边距=新厚度(0,1,0,0);
    }
    其他的
    {
    (topStack.Children[topStack.Children.Count-1]为椭圆)。边距=新厚度(8,1,0,0);
    }
    }
    }
    否则如果(_child.Pitch<0)
    {
    for(int i=0;i
    注:

  • 我不受这些代码的约束,所以如果你们中有人用完全不同的方法更有效地处理类似的事情,那么它总是受欢迎的
  • 抱歉,如果有语法错误,因为英语不是我的第一语言
  • 我觉得我没有真正清楚地解释我的问题,因为我对它也很困惑,所以,请澄清你需要的任何东西
  • 谢谢

    其他详情:

  • 理论上,圆点没有一定的限制,但实际上,它通常只有3个最大值(顶部3个或底部3个-不是两者都有)
  • 在我上面的代码中,note用户控件分为3个网格行,顶部的一个用于堆叠顶部的点,中间的一个用于可视化note(数字),bot的一个用于堆叠bot点
  • 请澄清任何事情,我会补充更多

  • 您应该使用ItemsControl来执行此操作,该控件为数字注释使用适当的
    ItemTemplate

    首先,创建一个ViewModel,定义“数字注释”项的集合:

    为了可视化音高,我建议使用一个
    路径
    对象,其几何体由许多椭圆几何组成。要实现这一点,您需要实现一个绑定转换器,将节数转换为几何体,如下所示。它使用Convert方法的
    参数
    参数为正螺距值或负螺距值创建几何图形

    public class NotePitchConverter : IValueConverter
    {
        private const double radius = 1.5;
        private const double distance = 2 * radius + 1;
    
        public object Convert(
            object value, Type targetType, object parameter, CultureInfo culture)
        {
            var pitch = (int)value;
            var geometry = new GeometryGroup();
    
            if (parameter as string == "Bottom")
            {
                pitch = -pitch;
            }
    
            for (int i = 0; i < pitch; i++)
            {
                geometry.Children.Add(new EllipseGeometry(
                    new Point(radius, radius + i * distance), radius, radius));
            }
    
            return geometry;
        }
    
        public object ConvertBack(
            object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotSupportedException();
        }
    }
    
    并编写如下所示的ItemsControl。请注意,DataTemplate对显示顶部和底部节距的路径元素使用固定高度。如果你需要显示三个以上的点,你需要增加它们的高度

    <ItemsControl ItemsSource="{Binding NumericNotes}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Grid Margin="2">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="12"/>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="12"/>
                    </Grid.RowDefinitions>
                    <Path Grid.Row="0" Fill="Black" HorizontalAlignment="Center"
                          VerticalAlignment="Bottom"
                          Data="{Binding Pitch,
                                 Converter={StaticResource NotePitchConverter}}"/>
                    <TextBlock Grid.Row="1" Text="{Binding Number}"/>
                    <Path Grid.Row="2" Fill="Black" HorizontalAlignment="Center"
                          VerticalAlignment="Top"
                          Data="{Binding Pitch,
                                 Converter={StaticResource NotePitchConverter},
                                 ConverterParameter=Bottom}"/>
                </Grid>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
    
    
    
    public class NotePitchConverter : IValueConverter
    {
        private const double radius = 1.5;
        private const double distance = 2 * radius + 1;
    
        public object Convert(
            object value, Type targetType, object parameter, CultureInfo culture)
        {
            var pitch = (int)value;
            var geometry = new GeometryGroup();
    
            if (parameter as string == "Bottom")
            {
                pitch = -pitch;
            }
    
            for (int i = 0; i < pitch; i++)
            {
                geometry.Children.Add(new EllipseGeometry(
                    new Point(radius, radius + i * distance), radius, radius));
            }
    
            return geometry;
        }
    
        public object ConvertBack(
            object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotSupportedException();
        }
    }
    
    <Window.Resources>
        <local:NotePitchConverter x:Key="NotePitchConverter"/>
    </Window.Resources>
    
    <ItemsControl ItemsSource="{Binding NumericNotes}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Grid Margin="2">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="12"/>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="12"/>
                    </Grid.RowDefinitions>
                    <Path Grid.Row="0" Fill="Black" HorizontalAlignment="Center"
                          VerticalAlignment="Bottom"
                          Data="{Binding Pitch,
                                 Converter={StaticResource NotePitchConverter}}"/>
                    <TextBlock Grid.Row="1" Text="{Binding Number}"/>
                    <Path Grid.Row="2" Fill="Black" HorizontalAlignment="Center"
                          VerticalAlignment="Top"
                          Data="{Binding Pitch,
                                 Converter={StaticResource NotePitchConverter},
                                 ConverterParameter=Bottom}"/>
                </Grid>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>