如何在WPF中创建包装按钮

如何在WPF中创建包装按钮,wpf,xaml,layout,button,Wpf,Xaml,Layout,Button,要求: 必须支持MinWidth属性 只能在一行或两行上显示文本。不能换行到3或更多 应使按钮尽可能小,同时考虑最小宽度 文本只能在空格上换行 无法指定宽度。按钮应保持水平生长 以下是我希望按钮的外观(请忽略样式,包装是重要部分) 我正在寻找如何使文本动态换行的方法。由于您将文本限制为两行,我的建议是编写一个自定义面板作为按钮内容,将指定的文本、字体等转换为WPF FormattedText对象。然后,您可以对其进行测量,并决定如何在MeasureOverride和ArrangeOverr

要求:

  • 必须支持MinWidth属性
  • 只能在一行或两行上显示文本。不能换行到3或更多
  • 应使按钮尽可能小,同时考虑最小宽度
  • 文本只能在空格上换行
  • 无法指定宽度。按钮应保持水平生长
以下是我希望按钮的外观(请忽略样式,包装是重要部分)


我正在寻找如何使文本动态换行的方法。

由于您将文本限制为两行,我的建议是编写一个自定义面板作为按钮内容,将指定的文本、字体等转换为WPF FormattedText对象。然后,您可以对其进行测量,并决定如何在MeasureOverride和ArrangeOverride中对其进行布局和显示。FormattedText甚至有一个参数来显示。。。如果文本不合适,请使用缩写。要将其保留为两行,您需要首先创建它,然后检查其高度,以查看一行的高度。(需要在注释中添加rest,因为StackOverflow正在抛出错误)。

我试图通过编辑
按钮的默认模板来实现这一点,主要是添加一个包装
文本块,而不是默认的
ContentPresenter
,并在转换器中计算其
宽度。虽然这种方法需要转换器中的大量数据,但可能有更简单(更好:)的方法来实现这一点,但它似乎无论如何都是可行的。由于默认模板中的
ButtonChrome
,它需要对PresentationFramework.Aero的引用

就这样用吧

<Button Style="{StaticResource WrappingButton}"
        MinWidth="100"
        Content="This button has some long text">
</Button>
包装按钮宽度转换器

public class WrappingButtonWidthConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        string text = values[0].ToString();
        FontFamily fontFamily = values[1] as FontFamily;
        FontStyle fontStyle = (FontStyle)values[2];
        FontWeight fontWeight = (FontWeight)values[3];
        FontStretch fontStretch = (FontStretch)values[4];
        double fontSize = (double)values[5];
        double minWidth = (double)values[6];

        string[] words = text.Split(new char[] {' '});
        double widthSum = 0.0;
        List<double> wordWidths = GetWordWidths(words, fontFamily, fontStyle, fontWeight, fontStretch, fontSize, out widthSum);

        double width = 0.0;
        for (int i = 0; width < (widthSum / 2.0) && i < wordWidths.Count; i++)
        {
            width += wordWidths[i];
        }

        return minWidth > 0.0 ? Math.Max(minWidth, width) : width;
    }
    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    private List<double> GetWordWidths(string[] words,
                                       FontFamily fontFamily,
                                       FontStyle fontStyle,
                                       FontWeight fontWeight,
                                       FontStretch fontStretch,
                                       double fontSize,
                                       out double widthSum)
    {
        List<double> wordWidths = new List<double>();
        widthSum = 0.0;
        foreach (string word in words)
        {
            Typeface myTypeface = new Typeface(fontFamily, fontStyle, fontWeight, fontStretch);
            FormattedText ft = new FormattedText(word + " ",
                                                 CultureInfo.CurrentCulture,
                                                 FlowDirection.LeftToRight,
                                                 myTypeface,
                                                 fontSize,
                                                 Brushes.Black);
            wordWidths.Add(ft.WidthIncludingTrailingWhitespace);
            widthSum += ft.WidthIncludingTrailingWhitespace;
        }
        return wordWidths;
    }
}
公共类包装按钮宽度转换器:IMultiValueConverter
{
公共对象转换(对象[]值,类型targetType,对象参数,System.Globalization.CultureInfo区域性)
{
字符串文本=值[0]。ToString();
FontFamily FontFamily=值[1]为FontFamily;
FontStyle FontStyle=(FontStyle)值[2];
FontWeight FontWeight=(FontWeight)值[3];
FontStretch FontStretch=(FontStretch)值[4];
double fontSize=(双)值[5];
double minWidth=(double)值[6];
string[]words=text.Split(新字符[]{''});
双宽度和=0.0;
List wordWidths=GetWordWidths(单词、fontFamily、fontStyle、fontWeight、fontStretch、fontSize、out widthSum);
双倍宽度=0.0;
对于(int i=0;宽度<(widthSum/2.0)和&i0.0?数学最大值(minWidth,width):宽度;
}
公共对象[]转换回(对象值,类型[]目标类型,对象参数,System.Globalization.CultureInfo区域性)
{
抛出新的NotImplementedException();
}
私有列表GetWordWidths(字符串[]字,
方氏家族方氏家族,
FontStyle FontStyle,
FontWeight FontWeight,
方拉伸方拉伸,
双倍大小,
输出双倍宽度(总和)
{
列表字宽=新列表();
宽度和=0.0;
foreach(单词中的字符串)
{
Typeface myTypeface=新字体(fontFamily、fontStyle、fontWeight、fontStretch);
FormattedText ft=新的FormattedText(word+“”,
CultureInfo.CurrentCulture,
FlowDirection.LeftToRight,
我的字体,
字体大小,
刷子(黑色);
字宽.Add(ft.width,包括trailingwhitespace);
宽度总和+=英尺宽度,包括牵引空白;
}
返回字宽;
}
}

使用RichTextBox作为按钮的内容:

            RichTextBox rtb = new RichTextBox();
            rtb.IsReadOnly = true;
            rtb.Focusable = false;
            rtb.BorderThickness = new Thickness(0);
            rtb.Background = Brushes.Transparent;
            rtb.AppendText("This button has some long text.");
            myButton.Content = rtb;

这件事是为我做的。还包括:

 <Window.Resources>
        <local:Questions x:Key="theQs"/>
        <Style x:Key="WrappingButton" TargetType="{x:Type Button}">
            <Setter Property="FontSize" Value="10">

            </Setter>
        </Style>
    </Window.Resources>

这是:

<Button Name="btnDef4" Grid.Row="3" Style="{StaticResource WrappingButton}" >
                <TextBlock Text="{Binding ElementName=LVQuestions, Path=SelectedItem.TheDefs[3].Deftext}"
                TextWrapping="Wrap"/>
            </Button>


然后,您可以将其MaxTextWidth设置为按钮宽度,然后再次检查英尺高度。如果它是原始高度的2倍以上,那么您有2条以上的线,并且希望将MaxHeight设置为原始高度的2倍左右。我将对此进行演示,并让您知道它是如何工作的。谢谢你的主意!我已经用它做了几乎完全一样的事情,所以如果它对你不起作用,请告诉我。我只需要在评论中发表评论,因为今天我发表短文以外的任何东西都会抛出错误。我有代码可以正确地将字符串拆分为行,但是您如何处理显示新拆分的行呢?我编写了一个简单的自定义面板。在MeasureOverride中,我使用了可用的大小来决定如何显示这些行(单行或双行)。在ArrangeOverride中,我只是按照MeasureOverride(修改格式化文本)中的布局放置它们,然后将文本居中放置。
<Button Name="btnDef4" Grid.Row="3" Style="{StaticResource WrappingButton}" >
                <TextBlock Text="{Binding ElementName=LVQuestions, Path=SelectedItem.TheDefs[3].Deftext}"
                TextWrapping="Wrap"/>
            </Button>