Могу ли я иметь полный контроль над рисованием пользовательской кнопки WPF? - PullRequest
0 голосов
/ 28 июня 2010

Полагаю, вы можете нарисовать много чего угодно с достаточным опытом работы с XAML, но я новичок в WPF на C ++. Мне нужна кнопка с градиентным цветом и специальной рамкой вокруг нее. Так, что мы, ребята из C ++, делаем? Мы идем к конструктору, запрашиваем левое вертикальное изображение, среднее и правое, а затем переписываем сообщения рисования Win32, сами рисуем кнопку.

Как WPF это делает? Нужно ли мне освоить XAML для этого или я могу как-то использовать эти 3 изображения для создания кнопки? Моя наивная мысль заключалась в том, чтобы сделать что-то вроде этого, когда я разделил кнопку на 3 части, каждая из которых имела разный фон, но это не дало мне желаемых результатов. Могу ли я контролировать, как нарисована кнопка?

<Style x:Key="NavButtonStyle" TargetType="{x:Type Button}">
        <Setter Property="OverridesDefaultStyle" Value="True" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Button}">
                    <Grid ShowGridLines="False">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*" />
                            <ColumnDefinition Width="*" />
                            <ColumnDefinition Width="*" />
                        </Grid.ColumnDefinitions>
                        <Grid Grid.Column="0">
                            <Grid.Background>
                                <ImageBrush ImageSource="/Images/left.png"/>
                            </Grid.Background>
                        </Grid>
                        <StackPanel Grid.Column="1" HorizontalAlignment="Center" Orientation="Horizontal">
                            <StackPanel.Background>
                                <ImageBrush Stretch="Fill" ImageSource="/Images/middle.png"/>
                            </StackPanel.Background>
                            <Image Source="/Images/Icons/myIcon.png"/>
                            <TextBlock Text="myCaption"/>
                        </StackPanel>
                        <Grid Grid.Column="2">
                            <Grid.Background>
                                <ImageBrush Stretch="Fill" ImageSource="/Images/right.png"/>
                            </Grid.Background>
                        </Grid>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

Другая проблема заключается в том, как сделать этот шаблон универсальным, чтобы я мог продублировать внешний вид, но просто изменить значок и текст. Я полагаю, правильный способ решения этой задачи - создать класс CustomControl, унаследованный от Button?

Ответы [ 2 ]

0 голосов
/ 28 июня 2010

Очень краткий ответ: для этого вы используете Expression Blend.

Немного менее краткий ответ заключается в том, что большинство из того, что вы описываете, может быть выполнено путем редактирования шаблона элемента управления, если вы понимаете, как работают шаблоны элементов управления, и знаете, что редактировать. Expression Blend - хороший инструмент для этого, потому что Blend делает редактирование шаблона элемента управления относительно простым и потому, что Blend запоминает многое, что вы, вероятно, забудете, особенно если вы относительно новичок в WPF.

Например, если я зайду в Blend, нарисую кнопку на артборде и отредактирую копию ее шаблона управления, вот что я получаю, прежде чем даже начать что-то связывать:

<Style x:Key="ButtonFocusVisual">
  <Setter Property="Control.Template">
    <Setter.Value>
      <ControlTemplate>
        <Rectangle Stroke="Black" StrokeDashArray="1 2" StrokeThickness="1" Margin="2" SnapsToDevicePixels="true"/>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>
<LinearGradientBrush x:Key="ButtonNormalBackground" EndPoint="0,1" StartPoint="0,0">
  <GradientStop Color="#F3F3F3" Offset="0"/>
  <GradientStop Color="#EBEBEB" Offset="0.5"/>
  <GradientStop Color="#DDDDDD" Offset="0.5"/>
  <GradientStop Color="#CDCDCD" Offset="1"/>
</LinearGradientBrush>
<SolidColorBrush x:Key="ButtonNormalBorder" Color="#FF707070"/>
<Style x:Key="ButtonControlTemplate" TargetType="{x:Type Button}">
  <Setter Property="FocusVisualStyle" Value="{StaticResource ButtonFocusVisual}"/>
  <Setter Property="Background" Value="{StaticResource ButtonNormalBackground}"/>
  <Setter Property="BorderBrush" Value="{StaticResource ButtonNormalBorder}"/>
  <Setter Property="BorderThickness" Value="1"/>
  <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
  <Setter Property="HorizontalContentAlignment" Value="Center"/>
  <Setter Property="VerticalContentAlignment" Value="Center"/>
  <Setter Property="Padding" Value="1"/>
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type Button}">
        <Microsoft_Windows_Themes:ButtonChrome x:Name="Chrome" SnapsToDevicePixels="true" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" RenderDefaulted="{TemplateBinding IsDefaulted}" RenderMouseOver="{TemplateBinding IsMouseOver}" RenderPressed="{TemplateBinding IsPressed}">
          <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" RecognizesAccessKey="True"/>
        </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>

В принципе, все, что вам нужно сделать, - это найти элемент ContentPresenter (в который вставляется содержимое кнопки) и заменить то, что его окружает, своей изящной вещью. Вы можете скопировать этот XAML в свой собственный проект и поэкспериментировать с ним, и вы получите что-то вроде этого.

Но: есть много вещей, которые вам нужно понять, прежде чем вы в конечном итоге создадите кнопку, которая на самом деле делает то, что вы хотите. Большинство из них представляет собой функциональность и поведение, которые, если вы похожи на меня, когда у вас есть блестящая идея разработать собственную кнопку, не заставят себя задуматься. Как:

  • Как должен измениться внешний вид кнопки, когда она имеет фокус?
  • Как должен измениться внешний вид кнопки, когда она отключена?
  • Какие события должны изменить внешний вид кнопки?

Если вы посмотрите на этот шаблон, вы заметите, что многие ответы на этот последний вопрос встроены в элемент Microsoft_Windows_Themes:ButtonChrome. Все, что он делает в коде (например, RenderPressed), это то, что вы должны встроить в свой XAML с помощью триггеров. (Или вы можете написать свой собственный объект, похожий на кнопку хрома.)

Полагаю, я говорю, что вы не на неправильном пути, но вам нужно многому научиться.

Что касается вашего второго вопроса, да, вы можете создать UserControl, который предоставляет свойства для заголовка и изображения. Вы также можете немного поэкспериментировать с тем фактом, что кнопка фактически является элементом управления контентом, например ::

<Button Height=50>
  <DockPanel>
    <Image Width="32" Source="image.png"/>
    <TextBlock Text="My button's caption" TextWrapping="Wrap" VerticalAlignment="Center"/>
  </DockPanel>
</Button>
0 голосов
/ 28 июня 2010

1 #: Я не знаю, что вы имеете в виду, получив контроль над кнопкой? Но у нас есть контроль, чтобы создать свой стиль кнопки, как вам нравится. В приведенном выше XAML я видел только шаблон, но нет триггеров или визуальных состояний, чтобы упоминать о различных состояниях / поведениях / эффектах кнопки, таких как наведение мыши, отпускание мыши, нажатие кнопки и т.д. эти эффекты будут работать как кнопки по умолчанию.

2 #: так как это пользовательский элемент управления, вы можете добавить стили в папку «Темы» и generic.xaml. Вы не должны указывать имя ключа, тогда оно будет применяться ко всем кнопкам пользовательского управления, как показано ниже:

<Style TargetType="{x:Type custom:CustomerControlType}"> 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...