Pergunta

Eu estou tentando fazer algum tipo de forma no WPF, que não redimensionar próprio para o conteúdo (que deve ser de texto). Infelizmente, a propriedade trecho não é a coisa certa, desde que eu quero apenas a largura da Forma redimensionada e sem as fronteiras (pls copiar exemplo fundo em XamlPad para ver por si mesmo) desta forma esticada. As fronteiras devem permanecer do jeito que são, ou pelo menos escala no uniforme. Eu tentei muitas idéias. Com diferentes fatias da forma de uma grade, StackPanel, ou com um painel cortado e etc. Meu próximo abordagem seria a seguinte:

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"><Page.Resources>
<LinearGradientBrush StartPoint="0.0,1" EndPoint="0.0,0" x:Key="brushYellow">
  <LinearGradientBrush.GradientStops>
    <GradientStop Offset="0.000000" Color="#fffef4a6"/>
    <GradientStop Offset="0.175824" Color="#fffef9d6"/>
    <GradientStop Offset="0.800000" Color="#fffef9d6"/>
    <GradientStop Offset="1.000000" Color="#fffef4a6"/>
  </LinearGradientBrush.GradientStops>
</LinearGradientBrush></Page.Resources><Grid>
 <Path Stroke="#fffce90d" StrokeThickness="1" Fill="{StaticResource brushYellow}">
    <Path.Data>
      <CombinedGeometry GeometryCombineMode="Exclude">
        <CombinedGeometry.Geometry1>
          <RectangleGeometry RadiusX="15" RadiusY="15">
            <!--RectangleGeometry.Rect>
              <Binding StringFormat="{}{0 0 {0} 82}" ElementName="Text" Path="Width"/>
            </RectangleGeometry.Rect-->
            <RectangleGeometry.Rect>
              <Rect Width="150" Height="82"/>
            </RectangleGeometry.Rect>
          </RectangleGeometry>
        </CombinedGeometry.Geometry1>
        <CombinedGeometry.Geometry2>
          <PathGeometry>
            <PathGeometry.Figures>
              <PathFigureCollection>
                <PathFigure IsClosed="True" StartPoint="0,15">
                  <PathFigure.Segments>
                    <PathSegmentCollection>
                      <LineSegment Point="17,41" />
                      <LineSegment Point="0,67" />
                    </PathSegmentCollection>
                  </PathFigure.Segments>
                </PathFigure>
              </PathFigureCollection>
            </PathGeometry.Figures>
          </PathGeometry>
        </CombinedGeometry.Geometry2>
      </CombinedGeometry>
    </Path.Data>
  </Path>
  <TextBox Name="Text" Background="Transparent" BorderThickness="0" MinWidth="150" Margin="0"/>
</Grid></Page>

Isto irá funcionar para fora da direita da caixa em XamlPad. A parte comentada na linha 19 é o que eu realmente deseja alcançar: Encadernação o Rect do retângulo para outra coisa. Infelizmente, a largura de Rect não é dp, é por isso que eu estou usando diretamente a stringformatted Encadernação para si Rect.

Como esperado com a vida, que não funciona (nada é visível): D O que estou fazendo de errado aqui?

Foi útil?

Solução

Eu uso um conjunto de classes chamado ViewboxPath, ViewboxLine, ViewboxPolyline, etc que mudar a semântica estiramento de forma a ser um pouco mais tratável. Eu não tenho certeza se entendi sua pergunta, então eu não sei se minha técnica vai resolver o seu problema ou não.

Como eu lê-lo, ou você quer controle sobre o alongamento, que esta solução irá fornecer, ou você quer ter os traços esticar junto com a imagem, que a resposta de Sam irá proporcionar.

De qualquer forma, abaixo é o código para essas classes e isso é como você usá-los:

<edf:ViewboxPolyline
    Viewbox="0 0 1 1"  <!-- Actually the default, can be omitted -->
    Stretch="Fill"     <!-- Also default, can be omitted -->
    Stroke="Blue"
    Points="0,0 0.2,0 0.2,0.3 0.4,0.3" />

<edf:ViewboxPolygon
    Viewbox="0 0 10 10"
    Stroke="Blue"
    Points="5,0 10,5 5,10 0,5" />

<edf:ViewboxPath
    Viewbox="0 0 10 10"
    Stroke="Blue"
    Data="M10,5 L4,4 L5,10" />

Meu classes de forma ViewBox são usados ??apenas como formas normais (Polyline, Polygon, Path e Line), exceto para o parâmetro Viewbox extra, e o fato de que eles padrão para Stretch="Fill". Os especifica parâmetros negatoscópio, no sistema de coordenadas usado para especificar a forma, a área da geometria que deve ser esticado usando as configurações Fill, Uniform ou UniformToFill, em vez de usar Geometry.GetBounds.

Isso dá um controle muito preciso sobre o alongamento e faz com que seja fácil ter formas separadas alinhar com precisão uns com os outros.

Aqui está o código real para minhas aulas forma Viewbox , incluindo o ViewboxShape classe base abstrata que contém funcionalidades comuns:

public abstract class ViewboxShape : Shape
{
  Matrix _transform;
  Pen _strokePen;
  Geometry _definingGeometry;
  Geometry _renderGeometry;

  static ViewboxShape()
  {
    StretchProperty.OverrideMetadata(typeof(ViewboxShape), new FrameworkPropertyMetadata
    {
      AffectsRender = true,
      DefaultValue = Stretch.Fill,
    });
  }

  // The built-in shapes compute stretching using the actual bounds of the geometry.
  // ViewBoxShape and its subclasses use this Viewbox instead and ignore the actual bounds of the geometry.
  public Rect Viewbox { get { return (Rect)GetValue(ViewboxProperty); } set { SetValue(ViewboxProperty, value); } }
  public static readonly DependencyProperty ViewboxProperty = DependencyProperty.Register("Viewbox", typeof(Rect), typeof(ViewboxShape), new UIPropertyMetadata
  {
    DefaultValue = new Rect(0,0,1,1),
  });

  // If defined, replaces all the Stroke* properties with a single Pen
  public Pen Pen { get { return (Pen)GetValue(PenProperty); } set { SetValue(PenProperty, value); } }
  public static readonly DependencyProperty PenProperty = DependencyProperty.Register("Pen", typeof(Pen), typeof(Pen), new UIPropertyMetadata
  {
    DefaultValue = null
  });

  // Subclasses override this to define geometry if caching is desired, or just override DefiningGeometry
  protected virtual Geometry ComputeDefiningGeometry()
  {
    return null;
  }

  // Subclasses can use this PropertyChangedCallback for properties that affect the defining geometry
  protected static void OnGeometryChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
  {
    var shape = sender as ViewboxShape;
    if(shape!=null)
    {
      shape._definingGeometry = null;
      shape._renderGeometry = null;
    }
  }

  // Compute viewport from box & constraint
  private Size ApplyStretch(Stretch stretch, Rect box, Size constraint)
  {
    double uniformScale;
    switch(stretch)
    {
      default:
        return new Size(box.Width, box.Height);

      case Stretch.Fill:
        return constraint;

      case Stretch.Uniform:
        uniformScale = Math.Min(constraint.Width / box.Width, constraint.Height / box.Height);
        break;

      case Stretch.UniformToFill:
        uniformScale = Math.Max(constraint.Width / box.Width, constraint.Height / box.Height);
        break;
    }
    return new Size(uniformScale * box.Width, uniformScale * box.Height);
  }

  protected override Size MeasureOverride(Size constraint)
  {
    // Clear pen cache if settings have changed
    if(_strokePen!=null)
      if(Pen!=null)
        _strokePen = null;
      else
        if(_strokePen.Thickness != StrokeThickness ||
           _strokePen.Brush != Stroke ||
           _strokePen.StartLineCap != StrokeStartLineCap ||
           _strokePen.EndLineCap != StrokeEndLineCap ||
           _strokePen.DashCap != StrokeDashCap ||
           _strokePen.LineJoin != StrokeLineJoin ||
           _strokePen.MiterLimit != StrokeMiterLimit ||
           _strokePen.DashStyle.Dashes != StrokeDashArray ||
           _strokePen.DashStyle.Offset != StrokeDashOffset)
          _strokePen = null;

    _definingGeometry = null;
    _renderGeometry = null;

    return ApplyStretch(Stretch, Viewbox, constraint);
  }

  protected override Size ArrangeOverride(Size availableSize)
  {
    Stretch stretch = Stretch;
    Size viewport;
    Matrix transform;

    // Compute new viewport and transform
    if(stretch==Stretch.None)
    {
      viewport = availableSize;
      transform = Matrix.Identity;
    }
    else
    {
      Rect box = Viewbox;
      viewport = ApplyStretch(stretch, box, availableSize);

      double scaleX = viewport.Width / box.Width;
      double scaleY = viewport.Height / box.Height;
      transform = new Matrix(scaleX, 0, 0, scaleY, -box.Left * scaleX, -box.Top * scaleY);
    }

    if(_transform!=transform)
    {
      _transform = transform;
      _renderGeometry = null;
      InvalidateArrange();
    }
    return viewport;
  }

  protected Pen PenOrStroke
  {
    get
    {
      if(Pen!=null)
        return Pen;
      if(_strokePen==null)
        _strokePen = new Pen
        {
          Thickness = StrokeThickness,
          Brush = Stroke,
          StartLineCap = StrokeStartLineCap,
          EndLineCap = StrokeEndLineCap,
          DashCap = StrokeDashCap,
          LineJoin = StrokeLineJoin,
          MiterLimit = StrokeMiterLimit,
          DashStyle =
            StrokeDashArray.Count==0 && StrokeDashOffset==0 ? DashStyles.Solid :
            new DashStyle(StrokeDashArray, StrokeDashOffset),
        };
      return _strokePen;
    }
  }

  protected Matrix Transform
  {
    get
    {
      return _transform;
    }
  }

  protected override Geometry DefiningGeometry
  {
    get
    {
      if(_definingGeometry==null)
        _definingGeometry = ComputeDefiningGeometry();
      return _definingGeometry;
    }
  }

  protected Geometry RenderGeometry
  {
    get
    {
      if(_renderGeometry==null)
      {
        Geometry defining = DefiningGeometry;
        if(_transform==Matrix.Identity || defining==Geometry.Empty)
          _renderGeometry = defining;
        else
        {
          Geometry geo = defining.CloneCurrentValue();
          if(object.ReferenceEquals(geo, defining)) geo = defining.Clone();

          geo.Transform = new MatrixTransform(
            geo.Transform==null ? _transform : geo.Transform.Value * _transform);
          _renderGeometry = geo;
        }
      }
      return _renderGeometry;
    }
  }

  protected override void OnRender(DrawingContext drawingContext)
  {
    drawingContext.DrawGeometry(Fill, PenOrStroke, RenderGeometry);
  }

}

[ContentProperty("Data")]
public class ViewboxPath : ViewboxShape
{
  public Geometry Data { get { return (Geometry)GetValue(DataProperty); } set { SetValue(DataProperty, value); } }
  public static readonly DependencyProperty DataProperty = DependencyProperty.Register("Data", typeof(Geometry), typeof(ViewboxPath), new UIPropertyMetadata
  {
    DefaultValue = Geometry.Empty,
    PropertyChangedCallback = OnGeometryChanged,
  });

  protected override Geometry DefiningGeometry
  {
    get { return Data ?? Geometry.Empty; }
  }
}

public class ViewboxLine : ViewboxShape
{
  public double X1 { get { return (double)GetValue(X1Property); } set { SetValue(X1Property, value); } }
  public double X2 { get { return (double)GetValue(X2Property); } set { SetValue(X2Property, value); } }
  public double Y1 { get { return (double)GetValue(Y1Property); } set { SetValue(Y1Property, value); } }
  public double Y2 { get { return (double)GetValue(Y2Property); } set { SetValue(Y2Property, value); } }
  public static readonly DependencyProperty X1Property = DependencyProperty.Register("X1", typeof(double), typeof(ViewboxLine), new FrameworkPropertyMetadata { PropertyChangedCallback = OnGeometryChanged, AffectsRender = true });
  public static readonly DependencyProperty X2Property = DependencyProperty.Register("X2", typeof(double), typeof(ViewboxLine), new FrameworkPropertyMetadata { PropertyChangedCallback = OnGeometryChanged, AffectsRender = true });
  public static readonly DependencyProperty Y1Property = DependencyProperty.Register("Y1", typeof(double), typeof(ViewboxLine), new FrameworkPropertyMetadata { PropertyChangedCallback = OnGeometryChanged, AffectsRender = true });
  public static readonly DependencyProperty Y2Property = DependencyProperty.Register("Y2", typeof(double), typeof(ViewboxLine), new FrameworkPropertyMetadata { PropertyChangedCallback = OnGeometryChanged, AffectsRender = true });

  protected override Geometry ComputeDefiningGeometry()
  {
    return new LineGeometry(new Point(X1, Y1), new Point(X2, Y2));
  }
}

[ContentProperty("Points")]
public class ViewboxPolyline : ViewboxShape
{
  public ViewboxPolyline()
  {
    Points = new PointCollection();
  }

  public PointCollection Points { get { return (PointCollection)GetValue(PointsProperty); } set { SetValue(PointsProperty, value); } }
  public static readonly DependencyProperty PointsProperty = DependencyProperty.Register("Points", typeof(PointCollection), typeof(ViewboxPolyline), new FrameworkPropertyMetadata
  {
    PropertyChangedCallback = OnGeometryChanged,
    AffectsRender = true,
  });

  public FillRule FillRule { get { return (FillRule)GetValue(FillRuleProperty); } set { SetValue(FillRuleProperty, value); } }
  public static readonly DependencyProperty FillRuleProperty = DependencyProperty.Register("FillRule", typeof(FillRule), typeof(ViewboxPolyline), new FrameworkPropertyMetadata
  {
    DefaultValue = FillRule.EvenOdd,
    PropertyChangedCallback = OnGeometryChanged,
    AffectsRender = true,
  });

  public bool CloseFigure { get { return (bool)GetValue(CloseFigureProperty); } set { SetValue(CloseFigureProperty, value); } }
  public static readonly DependencyProperty CloseFigureProperty = DependencyProperty.Register("CloseFigure", typeof(bool), typeof(ViewboxPolyline), new FrameworkPropertyMetadata
  {
    DefaultValue = false,
    PropertyChangedCallback = OnGeometryChanged,
    AffectsRender = true,
  });

  protected override Geometry  ComputeDefiningGeometry()
  {
    PointCollection points = Points;
    if(points.Count<2) return Geometry.Empty;

    var geometry = new StreamGeometry { FillRule = FillRule };
    using(var context = geometry.Open())
    {
      context.BeginFigure(Points[0], true, CloseFigure);
      context.PolyLineTo(Points.Skip(1).ToList(), true, true);
    }
    return geometry;
  }

}

public class ViewboxPolygon : ViewboxPolyline
{
  static ViewboxPolygon()
  {
    CloseFigureProperty.OverrideMetadata(typeof(ViewboxPolygon), new FrameworkPropertyMetadata
    {
      DefaultValue = true,
    });
  }
}

Aproveite!

Outras dicas

Você pode tentar usar uma transformação para alterar o tamanho do retângulo, em vez de ligação a largura do retângulo diretamente. Eu acho que isso deve funcionar.

por exemplo. colocar algo como este em sua tag RectangleGeometry :

<RectangleGeometry.Transform>
    <ScaleTransform ScaleX="{Binding ElementName=textBoxName, Path=Width, 
        Converter=MyScaleWidthConverter}" />
</RectangleGeometry.Transform>

Onde textBoxName é o nome da sua caixa de texto. não poderia trazer-me a chamá-lo de texto -. muito confuso

Você precisará fornecer um conversor para garantir a escala está correta - por exemplo, Você provavelmente vai querer voltar algo como Largura / 150 dado o seu código de exemplo.

Eu estou vendo um pouco estranho comportamento quando a largura do retângulo é definida como Auto no designer Visual Studio - Eu acho que esta é provavelmente uma peculiaridade designer. Deve funcionar uma vez que o conversor é ligado em tempo de execução.

Que tal usar o seu caminho como escova? No código a seguir eu uso um DrawingBrush como fundo para a própria caixa de texto ou como Fundo para uma Border delimitador. Apenas uma dica ... Espero que isso ajude.

<Window x:Class="MarkupWpf.BrushTest"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="BrushTest" Height="300" Width="300">
    <Window.Resources>
        <LinearGradientBrush StartPoint="0.0,1" EndPoint="0.0,0" x:Key="brushYellow">
            <LinearGradientBrush.GradientStops>
                <GradientStop Offset="0.000000" Color="#fffef4a6"/>
                <GradientStop Offset="0.175824" Color="#fffef9d6"/>
                <GradientStop Offset="0.800000" Color="#fffef9d6"/>
                <GradientStop Offset="1.000000" Color="#fffef4a6"/>
            </LinearGradientBrush.GradientStops>
        </LinearGradientBrush>
        <DrawingBrush x:Key="FabBrush">
            <DrawingBrush.Drawing>
                <GeometryDrawing Brush="{StaticResource brushYellow}">
                    <GeometryDrawing.Pen>
                        <Pen Thickness="1" Brush="#fffce90d" />
                    </GeometryDrawing.Pen>
                    <GeometryDrawing.Geometry>
                        <CombinedGeometry GeometryCombineMode="Exclude">
                            <CombinedGeometry.Geometry1>
                                <RectangleGeometry RadiusX="15" RadiusY="15">
                                    <RectangleGeometry.Rect>
                                        <Rect Width="150" Height="82"/>
                                    </RectangleGeometry.Rect>
                                </RectangleGeometry>
                            </CombinedGeometry.Geometry1>
                            <CombinedGeometry.Geometry2>
                                <PathGeometry>
                                    <PathGeometry.Figures>
                                        <PathFigureCollection>
                                            <PathFigure IsClosed="True" StartPoint="0,15">
                                                <PathFigure.Segments>
                                                    <PathSegmentCollection>
                                                        <LineSegment Point="17,41" />
                                                        <LineSegment Point="0,67" />
                                                    </PathSegmentCollection>
                                                </PathFigure.Segments>
                                            </PathFigure>
                                        </PathFigureCollection>
                                    </PathGeometry.Figures>
                                </PathGeometry>
                            </CombinedGeometry.Geometry2>
                        </CombinedGeometry>
                    </GeometryDrawing.Geometry>
                </GeometryDrawing>
            </DrawingBrush.Drawing>
        </DrawingBrush>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>
        <TextBox Grid.Row="0" Background="{StaticResource FabBrush}" BorderThickness="0" MinWidth="150" Margin="0"/>
        <Grid Grid.Row="1">
            <Border Background="{StaticResource FabBrush}">
                <TextBox Grid.Row="0" BorderThickness="0" MinWidth="150" Margin="20" />
            </Border>
        </Grid>
    </Grid>
</Window>

eu estou fazendo algo parecido com isto. eu quero formas personalizadas que automaticamente re tamanho quando eu redimensionar a janela. para a minha solução i derivado da forma e substituído a propriedade definingGeometry. Para as dimensões do meu forma i usar as propriedades ActualWidth e ActualHeight como estes reflectem a verdadeira largura e altura. Eu também estou overiding o método MeasureOverride () como este

        protected override Size MeasureOverride(Size constraint)
        {
            return this.DesiredSize;
        }

Eu estou gerando a forma no código usando (como eu disse antes) ActualWidth e ActualHeight como valores máximos. espero que isso ajude

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top