具有<path>内容和可视状态</path>的自定义Silverlight按钮

时间:2010-03-26 18:35:36

标签: silverlight-3.0 custom-controls user-controls

我想创建一个按钮控件,其中包含一个Path元素作为其内容 - 如果愿意,可以使用IconButton。

此按钮应满足两个条件:

1。 Path元素的笔触和填充颜色应该可供VisualStateManager操作。

2。 Path元素的数据字符串(定义它的形状)可以在代码或XAML中设置,这样我就可以创建几个这样的按钮,而无需为每个按钮创建一个新的自定义控件。

我能看到的唯一方法就是不涉及任何XAML。也就是说,在后面的代码中设置所有可视状态和动画,并逐点生成几何对象(并且无法在Path元素上使用方便的数据字符串属性)。

有更简单的方法吗?

修改

因此,我遇到的一个限制是Silverlight不支持PathGeometry中路径表达式的迷你语言,仅支持Path。我在其中一些图标中有一些详细的几何图形,我真的不想把我用Illustrator插件生成的方便的字符串(很确定它是this one)并将它们变成了单独的线段和曲线。

4 个答案:

答案 0 :(得分:1)

尼斯克里斯。如果要将路径存储为资源,可以稍微修改一下:

首先将依赖项属性更改为Path类型:

/// <summary>
/// Button that contains an icon, where the icon is drawn from a path.  
/// </summary>
public class IconButton : Button
{
    /// <summary>
    /// The path data that draws the icon. 
    /// </summary>
    public static readonly DependencyProperty IconPathProperty =
        DependencyProperty.Register("IconPath", typeof(Path), typeof(IconButton), new PropertyMetadata(default(Path)));

    /// <summary>
    /// Depencendy property backer. 
    /// </summary>
    public Path IconPath
    {
        get { return (Path)GetValue(IconPathProperty); }
        set { SetValue(IconPathProperty, value); }
    }

}

接下来,这是IconButton控件模板。

<!-- Icon Button Control Template -->
<ControlTemplate x:Key="IconButtonControlTemplate" TargetType="{x:Type usercontrols:IconButton}">
    <Grid x:Name="Grid">
        <Border SnapsToDevicePixels="True"  x:Name="Border" CornerRadius="1" BorderThickness="1" BorderBrush="{StaticResource ButtonBorderBrush}">
            <Path x:Name="Icon" Height="16" Width="16" Stretch="Fill"                                  
                Data="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IconPath.Data}" 
                    UseLayoutRounding="False" Grid.Column="1" VerticalAlignment="Center" Margin="0">
                <Path.Fill>
                    <SolidColorBrush x:Name="IconColor" Color="{Binding Color, Source={StaticResource ButtonIconBrush}}" />
                </Path.Fill>
            </Path>
        </Border>
    </Grid>
    <ControlTemplate.Triggers>
        <Trigger Property="IsKeyboardFocused" Value="true">
            <Setter Property="BorderBrush" Value="{StaticResource ButtonBorderBrush}" TargetName="Border"/>
        </Trigger>
        <Trigger Property="IsMouseOver" Value="true">
            <Setter Property="Background" Value="{StaticResource ButtonBackgroundMouseOverBrush}" TargetName="Border"/>
            <Setter Property="BorderBrush" Value="{StaticResource ButtonBorderMouseOverBrush}" TargetName="Border"/>
        </Trigger>
        <Trigger Property="IsPressed" Value="true">
            <Setter Property="Background" Value="{StaticResource ButtonBackgroundPressedBrush}" TargetName="Border"/>
        </Trigger>
        <Trigger Property="IsEnabled" Value="false">
            <Setter Property="Fill" Value="{StaticResource DisabledIconBrush}" TargetName="Icon"/>
            <Setter Property="Background" Value="{StaticResource ButtonBackgroundDisabledBrush}" TargetName="Border"/>
            <Setter Property="BorderBrush" Value="{StaticResource ButtonBorderDisabledBrush}" TargetName="Border"/>
        </Trigger>
    </ControlTemplate.Triggers>
</ControlTemplate>

...这里是使用此模板的IconButton样式,并添加了一些默认值:

<!-- Icon Button Style -->
<Style TargetType="{x:Type usercontrols:IconButton}">
    <Setter Property="FocusVisualStyle" Value="{DynamicResource SimpleButtonFocusVisual}"/>
    <Setter Property="HorizontalAlignment" Value="Left"/>
    <Setter Property="VerticalAlignment" Value="Top"/>
    <Setter Property="Height" Value="26"/>
    <Setter Property="Width" Value="26"/>
    <Setter Property="Margin" Value="5"/>
    <Setter Property="Content" Value="Button"/>
    <Setter Property="Template" Value="{StaticResource IconButtonControlTemplate}"/>
</Style>

现在您可以继续创建图标并将其保存在资源文件中:

<!-- Undo Icon -->
<Path x:Key="UndoIcon" Stretch="Fill" Data="F1 M 87.7743,80.7396L 87.5215,75.9539L 89.8692,74.2202C 89.9775,75.0329 90.0859,76.586 90.0859,76.5318C 92.9302,73.7417 97.5369,72.9755 100.208,76.2158C 102.019,78.413 102.258,81.2543 99.7657,83.9361C 97.2735,86.6179 92.6142,90.1124 92.6142,90.1124L 90.3748,87.6744L 97.3096,81.769C 97.3096,81.769 99.1516,79.9992 97.8514,78.3558C 96.2374,76.316 94.384,77.2542 92.1447,78.8795C 92.1176,78.9608 93.3998,79.1143 94.3118,79.2768L 92.4336,81.4439L 87.7743,80.7396 Z "/>


<!-- Filter Icon -->
<Path x:Key="FilterIcon" Stretch="Fill" Data="F1 M 6,16L 10,16L 10.0208,10L 16,3L 16,2.86102e-006L 0,9.53674e-007L 0,3L 6,10L 6,16 Z "/>

最后,创建按钮:

<usercontrols:IconButton IconPath="{StaticResource UndoIcon}"></usercontrols:IconButton>

答案 1 :(得分:0)

路径Data属性只是一个几何。当你说“几个这样的按钮”时,人们会假设有一些有限数量的按钮因Icon而异。

将每个“Icon”存储为ResourceGeictionary中的PathGeomerty,并将该ResourceDictionary作为app.xaml中的合并字典引用。

现在您可以简单地将几何分配到Path shap Data属性中。

答案 2 :(得分:0)

对于上面问题的第二部分,这里有一个kludge,它非常适合将字符串Path数据存储为资源并从代码中访问它们。

对于问题的第一部分,我刚刚在代码中创建了所有动画,将它们应用于鼠标事件,完全摆脱了XAML页面。

答案 3 :(得分:0)

这艘船可能早已航行,但我需要一些非常相似的东西,并且能够通过继承Button来推销我自己:

 public class PathButton : Button
    {
        public static readonly DependencyProperty PathDataProperty =
            DependencyProperty.Register("PathData", typeof(Geometry), typeof(PathButton), new PropertyMetadata(default(Geometry)));

        public Geometry PathData
        {
            get { return (Geometry) GetValue(PathDataProperty); }
            set { SetValue(PathDataProperty, value); }
        }

    }

                                                               

                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CommonStates">
                            <VisualStateGroup.Transitions>
                                <VisualTransition GeneratedDuration="0:0:0.1"/>
                            </VisualStateGroup.Transitions>
                            <VisualState x:Name="Normal"/>
                            <VisualState x:Name="MouseOver">
                                <Storyboard>                                    
                                    <ColorAnimation Duration="0" To="{StaticResource BlueColor}" Storyboard.TargetProperty="Color" Storyboard.TargetName="BackgroundRectangleColor" />
                                    <ColorAnimation Duration="0" To="{StaticResource WhiteColor}" Storyboard.TargetProperty="Color" Storyboard.TargetName="IconColor" />
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Pressed"/>
                            <VisualState x:Name="Disabled"/>
                        </VisualStateGroup>
                        <VisualStateGroup x:Name="FocusStates">
                            <VisualState x:Name="Unfocused"/>
                            <VisualState x:Name="Focused"/>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                    <Grid.Projection>
                        <PlaneProjection/>
                    </Grid.Projection>
                    <Rectangle x:Name="BackgroundRectangle" >
                        <Rectangle.Fill>
                            <SolidColorBrush x:Name="BackgroundRectangleColor" Color="{StaticResource GrayColor}" />
                        </Rectangle.Fill>   
                    </Rectangle>



                    <Path x:Name="Icon" Stretch="Fill"                                  
                    Data="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=PathData}" 
                        UseLayoutRounding="False" Grid.Column="1" Width="24" Height="24" VerticalAlignment="Center" Margin="0">
                        <Path.Fill>
                            <SolidColorBrush x:Name="IconColor" Color="{StaticResource LightGrayColor}" />
                        </Path.Fill>
                        </Path>
                    <TextBlock x:Name="Text" HorizontalAlignment="Center" TextWrapping="Wrap" Text="{TemplateBinding Content}" FontSize="9.333" FontFamily="Segoe UI Light" Foreground="{StaticResource LightGray}" Height="11" Margin="0,0,0,3" VerticalAlignment="Bottom"/>

                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    </Style>

使用示例:

<Controls:PathButton Content="Options" PathData="F1M50.6954,32.1146C50.7057,31.1041,50.6068,30.1107,50.4583,29.1459L54.5052,25.9193C53.4636,22.0377,51.4583,18.5612,48.7409,15.7604L43.9063,17.5885C42.3776,16.3229,40.6407,15.3099,38.7552,14.5814L37.9857,9.47656C36.1237,8.98181 34.1719,8.68225 32.1511,8.66663 30.1302,8.65625 28.1771,8.92578 26.2995,9.39844L25.4714,14.4948C23.5794,15.2057,21.8229,16.1901,20.2813,17.4401L15.4675,15.5521C12.7201,18.3138,10.6706,21.7631,9.57556,25.6328L13.582,28.9088C13.4193,29.875 13.3164,30.8658 13.3047,31.8776 13.2969,32.8984 13.3945,33.8854 13.5469,34.8588L9.49353,38.0807C10.5417,41.9584,12.5469,45.4401,15.2604,48.2383L20.0938,46.4127C21.6224,47.6744,23.3659,48.6875,25.2513,49.4193L26.0091,54.5234C27.8802,55.0209 29.8333,55.3177 31.8503,55.3334 33.8698,55.3385 35.8243,55.0729 37.6979,54.6041L38.5352,49.5C40.4219,48.7916,42.1784,47.806,43.7253,46.5664L48.53,48.4531C51.2813,45.6836,53.3268,42.233,54.4245,38.3685L50.418,35.0963C50.5833,34.1224,50.6862,33.1354,50.6954,32.1146 M31.9362,41.6615C26.6068,41.6302 22.3073,37.2734 22.3411,31.9375 22.3776,26.6002 26.7266,22.3008 32.0651,22.3359 37.4011,22.3698 41.7005,26.7252 41.6653,32.0625 41.629,37.4023 37.2786,41.6979 31.9362,41.6615"
        Style="{StaticResource PathButtonStyle1}" Grid.RowSpan="2" Grid.Column="1" />