2010-02-16 5 views
6

WPF의 컨트롤 템플릿에 대해 배우고 단추 모양을 사용자 지정 템플릿 스타일로 바꾸는 방법을 확인합니다. 원형 버튼을 만들기 위해서는 타원이 같은 높이와 너비로 정의되어야합니다. 관계없이 버튼 크기를 조정하는 방법의, 80 개 픽셀의 직경 원을 가지고 해당 스타일을 사용하는 모든 버튼을 강제하는 것이 물론크기를 조절할 수있는 버튼 컨트롤 템플릿

<Style x:Key="Button2" TargetType="Button"> 
    <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="Button"> 
       <Grid> 
        <Ellipse Fill="LightGreen" Width="80" Height="80"/> 
        <ContentPresenter HorizontalAlignment="Center" 
VerticalAlignment="Center"/> 
       </Grid> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
    <Setter Property="Control.Margin" Value="10"/> 
</Style> 

. 원이 높이/너비 값 중 더 짧은 값을 취할 수 있도록 버튼 크기에 따라을 동적으로 축척 할 수 있습니다 ().

그러나 순수 XAML 템플릿에서이 작업을 수행하는 방법을 가르치는 자료는 읽지 않았습니까? 이 효과를 얻으려면 코드 숨김이 필요합니다.

답변

6

여기서 TemplateBinding이옵니다 (TemplateBinding은 컨트롤 템플릿 내에서 사용되고 템플릿 컨트롤 (이 경우 Button)에서 값을 검색하는 데 사용됩니다). 이 사용의 짧은 형태이다

<Ellipse Fill="LightGreen" 
    Width="{TemplateBinding ActualWidth}" Height="{TemplateBinding ActualHeight}"/> 

참고 :

{Binding ActualWidth, RelativeSource={RelativeSource TemplatedParent}} 

TemplateBinding 태그 확장 단지에만 TemplatedParent 바인딩에 최적화되어 있습니다.

당신이 그것을 원형으로 만 원한다면, 타원이 W/H 중 더 작은 것이라면 내용이 쉽게 흐르지 않을 것입니다. 나는 당신이 실제로 원하는 것을 의심합니다. 다중 값 변환기를 사용하여 생각 했었지만 변환기 매개 변수에 바인딩 할 수 없으므로 예외가 발생했습니다.

이 경우 연결된 동작이 작동하지만 꽤 좋지는 않습니다.

<Window x:Class="WpfApplication1.Window1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:c="clr-namespace:WpfApplication1" 
    xmlns:local="clr-namespace:WpfApplication1" 
    Title="Window1" Height="300" Width="300"> 

    <Grid> 
     <Button Content="Yo!" Width="50" Height="30"> 
      <Button.Template> 
       <ControlTemplate TargetType="Button"> 
        <Grid> 
         <Ellipse Fill="LightGreen" local:ConstrainWidthHeight.ConstrainedWidth="{TemplateBinding ActualWidth}" local:ConstrainWidthHeight.ConstrainedHeight="{TemplateBinding ActualHeight}"/> 
         <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/> 
        </Grid> 
       </ControlTemplate> 
      </Button.Template> 
     </Button> 
    </Grid> 
</Window> 

... 그리고 첨부 된 행동 : 연결된 동작 (AFAICT 어쨌든)가 필요합니다 사용하는 이유

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Windows; 

namespace WpfApplication1 { 
    public class ConstrainWidthHeight { 
     public static readonly DependencyProperty ConstrainedWidthProperty = 
      DependencyProperty.RegisterAttached("ConstrainedWidth", typeof(double), typeof(ConstrainWidthHeight), new PropertyMetadata(double.NaN, OnConstrainValuesChanged)); 
     public static readonly DependencyProperty ConstrainedHeightProperty = 
      DependencyProperty.RegisterAttached("ConstrainedHeight", typeof(double), typeof(ConstrainWidthHeight), new UIPropertyMetadata(double.NaN, OnConstrainValuesChanged)); 

     public static double GetConstrainedHeight(FrameworkElement obj) { 
      return (double) obj.GetValue(ConstrainedHeightProperty); 
     } 

     public static void SetConstrainedHeight(FrameworkElement obj, double value) { 
      obj.SetValue(ConstrainedHeightProperty, value); 
     } 

     public static double GetConstrainedWidth(FrameworkElement obj) { 
      return (double) obj.GetValue(ConstrainedWidthProperty); 
     } 

     public static void SetConstrainedWidth(FrameworkElement obj, double value) { 
      obj.SetValue(ConstrainedWidthProperty, value); 
     } 

     private static void OnConstrainValuesChanged(object sender, DependencyPropertyChangedEventArgs e) { 
      FrameworkElement element = sender as FrameworkElement; 
      if(element != null) { 
       double width = GetConstrainedWidth(element); 
       double height = GetConstrainedHeight(element); 

       if(width != double.NaN && height != double.NaN) { 
        double value = Math.Min(width, height); 

        element.Width = value; 
        element.Height = value; 
       } 
      } 
     } 
    } 
} 

자, 이제 이유, 그거에 (타원의 중심을하기 위해 비 정사각형/비 원형 시나리오), HorizontalAlignment 및 VerticalAlignment를 적용해야합니다. 기본값은 모두 Stretch이며, 명시적인 Width/Height가 설정되면 Center와 같이 작동합니다.

Stretch = "Uniform"을 설정하면 타원은 항상 전체 공간을 물리적으로 차지하게되며, 제한 될 타원의 그리기 일뿐입니다. 이를 사용하여 그려진 타원 그림은 항상 왼쪽 상단부터 시작합니다. 따라서이 경우 높이가 너비보다 넓 으면 타원의 그려진 부분이 텍스트와 함께 중앙에 오지 않습니다.

이 코드는 아마 찾는 게 무엇의 좋은 예입니다

<Ellipse Height="{TemplateBinding ActualHeight}" Width="{TemplateBinding ActualWidth}" Fill="LightGreen" Stretch="Uniform" /> 

... 그리고 버튼 (비 사각형 너비/높이)를 사용하여 :

<Button Content="YO!" Style="{StaticResource Button2}" Width="120" Height="53" VerticalAlignment="Top"></Button> 

은 다음과 같습니다

Ugly http://www.freeimagehosting.net/uploads/84e62c4982.png

...첨부 된 속성 옵션이 비교 : 자동 민 (높이, 폭) 당신은 아담이 시사하는 등 연결된 속성을 필요 없어요처럼 작동 것이다 타원에

alt text http://www.freeimagehosting.net/uploads/40755babcd.png

+0

확인 타원도 원 모양이 대형으로 크기를 조정 한 후 사라지게에 난이 방법을 시도하고 그것은 = "센터"HorizontalAlignment로 = "센터"VerticalAlignment을 적용하는 것 같다 크기. 나는 무슨 일이 일어나고 있는지 궁금해. – icelava

+0

ActualWidth 및 ActualHeight를 사용하여 내 대답이 업데이트되었습니다. 승/구속력에 묶는 것은 왜 당신이보고있는 것을하고 있는지입니다. –

+0

ActualWidth 및 ActualHeight로 변경하면 현재 중앙에 렌더링 된 것처럼 보입니다. 나는 아직도 왜 완전히 이해하지 못했지만, 고마워. – icelava

0

설정 스트레치 = 통일.

<Style x:Key="Button2" TargetType="Button"> 
     <Setter Property="Template"> 
      <Setter.Value> 
       <ControlTemplate TargetType="Button"> 
        <Grid> 
         <Ellipse Height="{TemplateBinding Height}" Width="{TemplateBinding Width}" Fill="LightGreen" Stretch="Uniform"/> 
         <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/> 
        </Grid> 
       </ControlTemplate> 
      </Setter.Value> 
     </Setter> 
    </Style> 
+0

이 형식은 작동하지만 HorizontalAlignment = "Center"VerticalAlignment = "Center"를 Ellipse 요소에 추가하여 ContentPresenter와 함께 중앙 집중 시키면 사라집니다. 어떤 아이디어? – icelava

1

stretch=uniform 인 타원체 개체에 그리드를 채우지 만 범위를 벗어나지 않습니다. 그래도 괜찮습니다. 그리드가 완벽하게 사각형이 아닐 경우 원이 중앙에 배치되지 않습니다. 뷰 박스에 타원 배치

날 문제 해결 :

<Grid> 
    <Viewbox> 
     <Ellipse Stretch="Uniform"/> 
    </Viewbox> 
</Grid> 

여기 유일한 문제는 타원의 기본 크기가을 이용하여 즉, (있는지 또는 1 생략) 0 있다는 stroke은 타원 전체를 자동으로 채 웁니다 (획은 0 크기 타원에 설정되고 타원은 크기가 조정됩니다).

<Style x:Key="BaseCoilEllipse" TargetType="Ellipse"> 
    <Setter Property="MinHeight" Value="10" /> 
    <Setter Property="MinWidth" Value="10" /> 
    <!-- Because the ellipse is inside a viewbox, the stroke will be dependant on MinHight/MinWidth. 
     Basically the stroke will now be 4/10th of the ellipse (strokethickness*2/MinHeight/MinWidth) --> 
    <Setter Property="StrokeThickness" Value="2"/> 
    <Setter Property="Stroke" Value="Green" /> 

    <Setter Property="Stretch" Value="Uniform" /> 
    <Setter Property="Fill" Value="Black"/> 
</Style> 
: 다음 스타일을 사용하여

<Grid Background="Yellow"> 
    <Viewbox> 
     <Ellipse Style="{Binding Path=StyleStatus, ConverterParameter='CoilEllipse', Converter={StaticResource styleConverter}}"/> 
    </Viewbox> 
</Grid> 

:

스트로크가 작동하지 않습니다에 대한 해결 방법은, 타원의 중요 minHeight/minWidth를 사용하는 것입니다 : 뇌졸중으로

(StrokeThickness는 현재 이며 상대적 임)

결과 :

Centered ellipse with stroke

관련 문제