2011-07-28 14 views
5

Requisitos:Cómo crear un botón de envolver en WPF

  • debe ser compatible con la propiedad MinWidth
  • puede mostrar texto en sólo una o dos líneas. No se puede ajustar a 3 o más.
  • botón debe hacer lo más pequeño posible, respetando MinWidth
  • texto puede envolver sólo en espacios
  • No se puede especificar la anchura. El botón debe seguir creciendo horizontalmente.

Esto es lo que me gustaría que los botones para parecerse a (Ignorar el estilo por favor, la envoltura es la parte importante)

enter image description here

Busco ideas sobre cómo hacer que el texto envolver dinámicamente

Respuesta

1

Como ha limitado el texto a dos líneas, mi sugerencia sería escribir un panel personalizado como el contenido del botón que convierte el texto, la fuente, etc. especificado en un objeto WPF FormattedText. Luego puede medirlo y decidir cómo desea que se distribuya y muestre en MeasureOverride y ArrangeOverride. FormattedText incluso tiene un parámetro para mostrar una ... abreviación si el texto no encaja. Para mantenerlo en dos líneas, primero debería crearlo, luego verifique su altura para ver qué es una sola línea para la altura. (necesita agregar resto en los comentarios ya que StackOverflow está lanzando errores).

+0

A continuación, puede establecer su MaxTextWidth a la anchura botón, a continuación, comprobar el ft.Height nuevo. Si es más de 2 veces la altura original, tiene más de 2 líneas y desea establecer MaxHeight a aproximadamente 2 veces la altura original. –

+0

Le daré una oportunidad y le haré saber cómo funciona. ¡Gracias por la idea! –

+0

He hecho casi exactamente esto, así que si no funciona, házmelo saber. Solo tengo que publicar en los comentarios ya que SO hoy arroja errores cuando hago cualquier cosa menos publicaciones cortas. –

2

Me trataron de lograr esto mediante la edición de la plantilla predeterminada para Button, principalmente agregando un envoltorio TextBlock en lugar del predeterminado ContentPresenter y calcular su Width en un convertidor. Sin embargo, este enfoque requería casi todos los datos en el convertidor. Hay maneras más fáciles (y mejores) de hacerlo, pero parece que funciona de todos modos. Se necesita una referencia al PresentationFramework.Aero debido a la ButtonChrome en la plantilla predeterminada

sólo lo utilizan como esto

<Button Style="{StaticResource WrappingButton}" 
     MinWidth="100" 
     Content="This button has some long text"> 
</Button> 

enter image description here
muestra de captura de pantalla con 3 WrappingButtons en un StackPanel

WrappingButton Style

<Style x:Key="WrappingButton" TargetType="{x:Type Button}" 
     xmlns:Microsoft_Windows_Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"> 
    <Setter Property="HorizontalAlignment" Value="Left"/> 
    <Setter Property="Width" Value="Auto"/> 
    <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="{x:Type Button}"> 
       <ControlTemplate.Resources> 
        <local:WrappingButtonWidthConverter x:Key="WrappingButtonWidthConverter"/> 
       </ControlTemplate.Resources> 
       <Microsoft_Windows_Themes:ButtonChrome x:Name="Chrome" BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" RenderMouseOver="{TemplateBinding IsMouseOver}" RenderPressed="{TemplateBinding IsPressed}" RenderDefaulted="{TemplateBinding IsDefaulted}" SnapsToDevicePixels="true"> 
        <TextBlock VerticalAlignment="Center" 
           FontSize="{TemplateBinding FontSize}" 
           FontFamily="{TemplateBinding FontFamily}" 
           FontStyle="{TemplateBinding FontStyle}" 
           FontWeight="{TemplateBinding FontWeight}" 
           FontStretch="{TemplateBinding FontStretch}" 
           LineStackingStrategy="BlockLineHeight" 
           TextWrapping="Wrap" 
           TextTrimming="WordEllipsis" 
           Text="{Binding RelativeSource={RelativeSource TemplatedParent}, 
               Path=Content}"> 
         <TextBlock.Width> 
          <MultiBinding Converter="{StaticResource WrappingButtonWidthConverter}"> 
           <Binding RelativeSource="{RelativeSource Self}" Path="Text"/> 
           <Binding RelativeSource="{RelativeSource TemplatedParent}" Path="FontFamily"/> 
           <Binding RelativeSource="{RelativeSource TemplatedParent}" Path="FontStyle"/> 
           <Binding RelativeSource="{RelativeSource TemplatedParent}" Path="FontWeight"/> 
           <Binding RelativeSource="{RelativeSource TemplatedParent}" Path="FontStretch"/> 
           <Binding RelativeSource="{RelativeSource TemplatedParent}" Path="FontSize"/> 
           <Binding RelativeSource="{RelativeSource TemplatedParent}" Path="MinWidth"/> 
          </MultiBinding> 
         </TextBlock.Width> 
        </TextBlock> 
       </Microsoft_Windows_Themes:ButtonChrome> 
       <ControlTemplate.Triggers> 
        <Trigger Property="IsKeyboardFocused" Value="true"> 
         <Setter Property="RenderDefaulted" TargetName="Chrome" Value="true"/> 
        </Trigger> 
        <Trigger Property="ToggleButton.IsChecked" Value="true"> 
         <Setter Property="RenderPressed" TargetName="Chrome" Value="true"/> 
        </Trigger> 
        <Trigger Property="IsEnabled" Value="false"> 
         <Setter Property="Foreground" Value="#ADADAD"/> 
        </Trigger> 
       </ControlTemplate.Triggers> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
</Style> 

WrappingButtonWidthConverter

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; 
    } 
} 
0

Utilice un RichTextBox como el contenido de su botón:

  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; 
1

http://wpf.2000things.com/2011/07/11/339-wrapping-a-buttons-text-content-to-multiple-lines/

esto tengo hecho para mí.También esto:

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

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

y esto:

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