开发者

XAML Path sizing and positioning

I am trying to design a template for a TabItem using paths and rectangles. The sides of the tab layout are paths to accommodate curves in the design. I am having a problem with getting the sides to line up/resize correctly. Here's my XAML:

<StackPanel Orientation="Horizontal">
 <Path Stretch="UniformToFill" Fill="#FF000000" Data="F1 M 97.1985,101.669L 104.824,95.0005C 105.574,94.3338 106.921,93.8627 107.824,93.9171L 107.824,101.667L 97.1985,101.669 Z "/>
 <Grid>
          <Rectangle Grid.Column="1" Fill="#FF000000"/>
  <ContentControl Grid.Column="1" x:Name="HeaderTopSelected" FontSize="{TemplateBinding FontSize}" Foreground="{TemplateBinding Foreground}" IsTabStop="False" Cursor="{TemplateBinding Cursor}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" VerticalAlignment="{TemplateBinding VerticalAlignment}"/>
 </Grid>
 <Path Stretch="UniformToFill" Fill="#FF000000" Data="F1 M 118.714,101.678L 111.088,95.0097C 110.338,94.343 108.991,93.8719 108.088,93.9264L 108.088,101.676L 118.714,101.678 Z "/>
</StackPanel>

(I apologize for the lack of line breaks. I'm new to StackOverflow and don't know how to insert them, nor do I have the time to figure it out :D)

The code snippet posted almost works: The side paths are the correct size, but they do not display in a line, they overlap behind the rectangle/next element. If I set a fixed width they work as well, but I can't set the width as fixed, they need to be fluid in case the content of the tab exceeds the basic height.

This is开发者_如何转开发 an idea of what I would like to get

The sides (paths) grow uniformally based on the height of the ContentControl


Take 3 (now we know what the requirement is):

Basically to get the desired effect you need your 2 side parts to resize their width if their height changes, in order to keep a fixed aspect ratio. This will force the parent container to expand as the actual content gets taller and the sides get taller to match. none of the containers (including ViewBox) work exactly this way.

You could use a custom container to do this, but the preferred solution would be to create a behaviour that retains its object's aspect ratio on height changes. We will call it a FixedAspectBehavior:

using System.Windows;
using System.Windows.Interactivity;

namespace SilverlightApplication1
{
    public class FixedAspectRatioBehavior : TargetedTriggerAction<FrameworkElement>
    {
        public double AspectRatio { get; set; }

        protected override void OnAttached()
        {
            base.OnAttached();
            FrameworkElement element = this.AssociatedObject as FrameworkElement;
            if (element != null)
            {
                AspectRatio = element.Width/element.Height;
                element.SizeChanged += new SizeChangedEventHandler(element_SizeChanged);
            }
        }

        void element_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            FrameworkElement element = AssociatedObject as FrameworkElement;
            element.Width = element.Height * AspectRatio;
        }

        protected override void Invoke(object parameter)
        {
        }
    }
}

The layout requires some work as self resizing elements (of type path) do some very weird things depending on their parent container. I had to use ViewBoxes as the parent of the paths, combined with the behaviours to get the desired result:

XAML Path sizing and positioning

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
    <Viewbox>
            <Path Stretch="UniformToFill" Fill="#FF000000" Data="F1 M 97.1985,101.669L 104.824,95.0005C 105.574,94.3338 106.921,93.8627 107.824,93.9171L 107.824,101.667L 97.1985,101.669 Z " UseLayoutRounding="False" HorizontalAlignment="Left">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="MouseLeftButtonDown">
                        <local:FixedAspectRatioBehavior/>
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </Path>
        </Viewbox>
    <Grid Width="Auto" Background="#FFFF0D0D" Grid.ColumnSpan="1" Grid.Column="1">
        <Rectangle Grid.Column="1" Fill="#FFD21F1F"/>
        <ContentControl Grid.Column="1" x:Name="HeaderTopSelected" FontSize="{TemplateBinding Control.FontSize}" Foreground="{TemplateBinding Control.Foreground}" IsTabStop="False" Cursor="{TemplateBinding FrameworkElement.Cursor}" HorizontalAlignment="{TemplateBinding FrameworkElement.HorizontalAlignment}" VerticalAlignment="{TemplateBinding FrameworkElement.VerticalAlignment}"/>
        <TextBlock TextWrapping="Wrap" FontSize="16"><Run Text="This is just a very string to see "/><LineBreak/><Run Text="what happens  when we get to a size where the container should get larger than the default size"/></TextBlock>
    </Grid>
    <Viewbox Grid.Column="2">
        <Path Stretch="UniformToFill" Fill="#FF000000" Data="F1 M 118.714,101.678L 111.088,95.0097C 110.338,94.343 108.991,93.8719 108.088,93.9264L 108.088,101.676L 118.714,101.678 Z " UseLayoutRounding="False" d:LayoutOverrides="VerticalAlignment">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="MouseLeftButtonDown">
                    <local:FixedAspectRatioBehavior/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Path>
    </Viewbox>
        </Grid>

Take 1 (obsolete now, as is 2 below):

The width of a path does not push along items in a stack panel. In that respect it's width is useless except to scale the item.

To get the effect you wanted, group each path into a grid. The size problem then goes away.

XAML Path sizing and positioning

Apologies for turning your rectangle horrible red to show it clearly :)

XAML Path sizing and positioning

XAML below:

<StackPanel Orientation="Horizontal" Width="Auto">
    <Grid>
        <Path Stretch="UniformToFill" Fill="#FF000000" Data="F1 M 97.1985,101.669L 104.824,95.0005C 105.574,94.3338 106.921,93.8627 107.824,93.9171L 107.824,101.667L 97.1985,101.669 Z " UseLayoutRounding="False" d:LayoutOverrides="Width"/>
    </Grid>
    <Grid Width="100" Background="#FFFF0D0D">
        <Rectangle Grid.Column="1" Fill="#FFD21F1F"/>
        <ContentControl Grid.Column="1" x:Name="HeaderTopSelected" FontSize="{TemplateBinding Control.FontSize}" Foreground="{TemplateBinding Control.Foreground}" IsTabStop="False" Cursor="{TemplateBinding FrameworkElement.Cursor}" HorizontalAlignment="{TemplateBinding FrameworkElement.HorizontalAlignment}" VerticalAlignment="{TemplateBinding FrameworkElement.VerticalAlignment}"/>
    </Grid>
    <Grid>
        <Path Stretch="UniformToFill" Fill="#FF000000" Data="F1 M 118.714,101.678L 111.088,95.0097C 110.338,94.343 108.991,93.8719 108.088,93.9264L 108.088,101.676L 118.714,101.678 Z " UseLayoutRounding="False" d:LayoutOverrides="Width"/>
    </Grid>
</StackPanel>

Take 2 (also obsolete now, see take 3 at the top):

If you require fixed end widths, use a grid instead of a stack panel (XAML below).

XAML Path sizing and positioning

If you require something else, please provide a couple of screen shots of the desired effect.

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="100"/>
            <ColumnDefinition/>
            <ColumnDefinition Width="100"/>
        </Grid.ColumnDefinitions>
    <Path Stretch="Fill" Fill="#FF000000" Data="F1 M 97.1985,101.669L 104.824,95.0005C 105.574,94.3338 106.921,93.8627 107.824,93.9171L 107.824,101.667L 97.1985,101.669 Z " UseLayoutRounding="False" d:LayoutOverrides="Width"/>
    <Grid Width="Auto" Background="#FFFF0D0D" Grid.ColumnSpan="1" Grid.Column="1">
        <Rectangle Grid.Column="1" Fill="#FFD21F1F"/>
        <ContentControl Grid.Column="1" x:Name="HeaderTopSelected" FontSize="{TemplateBinding Control.FontSize}" Foreground="{TemplateBinding Control.Foreground}" IsTabStop="False" Cursor="{TemplateBinding FrameworkElement.Cursor}" HorizontalAlignment="{TemplateBinding FrameworkElement.HorizontalAlignment}" VerticalAlignment="{TemplateBinding FrameworkElement.VerticalAlignment}" Content="Hello there.... this is a long string to see what happens"/>
    </Grid>
    <Path Stretch="Fill" Fill="#FF000000" Data="F1 M 118.714,101.678L 111.088,95.0097C 110.338,94.343 108.991,93.8719 108.088,93.9264L 108.088,101.676L 118.714,101.678 Z " UseLayoutRounding="False" d:LayoutOverrides="Width" Grid.Column="2"/>
        </Grid>
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜