Пользовательская кнопка Silverlight с содержимым <Path>и визуальными состояниями - PullRequest
0 голосов
/ 26 марта 2010

Я хотел бы создать элемент управления кнопки, который имеет элемент Path в качестве содержимого - IconButton, если хотите.

Эта кнопка должна удовлетворять двум условиям:

1. Цвета обводки и заливки элемента Path должны быть доступны для работы с VisualStateManager.

2. Строка данных элемента Path (которая определяет его форму) может быть задана в коде или в XAML, так что я могу создать несколько таких кнопок без создания нового пользовательского элемента управления для каждого.

Единственный способ, которым я могу это сделать, - это не задействовать XAML вообще. То есть установка всех визуальных состояний и анимаций в коде, а также генерация объектов Geometry по точкам (и невозможность использовать удобное свойство Data в элементе Path).

Есть ли более простой способ сделать это?

EDIT

Итак, одно из ограничений, с которыми я сталкиваюсь, заключается в том, что Silverlight не поддерживает мини-язык для выражений пути в PathGeometry, только в Path. У меня есть некоторая подробная геометрия в некоторых из этих значков, и я действительно не хочу брать удобные строки, которые я сгенерировал с помощью плагина Illustrator (почти наверняка это было это ) сделайте их отдельными отрезками и кривыми.

Ответы [ 4 ]

1 голос
/ 06 августа 2012

Хороший Крис. Если вы хотите сохранить пути как ресурсы, вы можете изменить их так:

Сначала измените свойство зависимости на тип 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>

0 голосов
/ 30 марта 2010

Для второй части проблемы, приведенной выше, вот kludge , который очень хорошо работает для хранения данных строки Path в качестве ресурсов и доступа к ним из кода.

Для первой части проблемы я просто создал все анимации в коде, применил их к событиям мыши, полностью избавился от страницы XAML.

0 голосов
/ 04 мая 2012

Этот корабль, возможно, уже давно отплыл, но мне нужно было что-то очень похожее, и я смог сделать свой собственный, унаследовав от 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" />
0 голосов
/ 27 марта 2010

Свойство Path Data - это просто геометрия. Когда вы говорите «несколько таких кнопок», подразумевается, что таких кнопок конечное количество, которые меняются в зависимости от значка.

Сохраняйте каждый «Icon» как PathGeomerty в ResourceDictionary, а ResourceDictionary упоминается как объединенный словарь в app.xaml.

Теперь вы можете просто назначить geomerty в свойстве Path shap Data.

...