2014-06-11 13 views
5

I È necessario creare un modello PrograssBar rotondo.WPF Clipping A Border

ControlTemplate:

<ControlTemplate TargetType="{x:Type ProgressBar}"> 
    <Grid x:Name="TemplateRoot" SnapsToDevicePixels="true">      
    <Rectangle x:Name="PART_Track" Margin="1" Fill="White" /> 

    <Border x:Name="PART_Indicator" HorizontalAlignment="Left" Margin="1" > 
     <Grid x:Name="Foreground" > 
      <Rectangle x:Name="Indicator" Fill="{TemplateBinding Background}" /> 
      <Grid x:Name="Animation" ClipToBounds="true" > 
       <Rectangle x:Name="PART_GlowRect" Fill="#FF86C7EB" HorizontalAlignment="Left" Margin="-100,0,0,0" Width="100"/> 
      </Grid>        
     </Grid>                
    </Border> 

    <Border x:Name="roundBorder" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="10" /> 
    <TextBlock /> 

    </Grid> 
</ControlTemplate> 

Ciò comporta:

enter image description here

Dove Part_Indicator è il rettangolo LightBlue sulla sinistra (è larghezza viene impostato internamente nel controllo PrograssBar, come visto qui con un valore di 20) e il 'roundBorder'.

cosa ho bisogno è per il il PART_Indicator alla clip sul roundBorder, con conseguente qualcosa in questo modo:

enter image description here

+2

Controllare [questo] (http://stackoverflow.com/questions/5649875/wpf-how-to-make-the-border-trim-the-child-elements) domanda. Potrebbe esserti d'aiuto – dkozl

+0

PER VIA per chi guarda questa domanda. La risposta qui sotto. purtroppo con lo 0 voti su di esso. Funziona alla grande. è la strada da percorrere. nessun convertitore. nessuna influenza aggiuntiva sul modello basata su elementi del controllo. semplice ritaglio durante la conservazione. –

risposta

5

C'è una proprietà ClipToBounds sulla classe Border che dovrebbe agganciare il contenuto in i limiti della Border, ma purtroppo, non 'fare quello che dice sulla latta':

<Border CornerRadius="25" BorderBrush="RoyalBlue" BorderThickness="3" Width="300" 
    Height="50" ClipToBounds="True"> <!-- This doesn't work as expected --> 
    <Rectangle Fill="SkyBlue" /> 
</Border> 

Tuttavia, la classe Rectangle fornisce anche alcune proprietà che potrebbero essere di aiuto. C'è qualcosa che impedisce di solo utilizzando le proprietà Rectangle.RadiusX e Rectangle.RadiusY per arrotondare gli angoli Rectangle ?:

<Border CornerRadius="25" BorderBrush="RoyalBlue" BorderThickness="3" Width="300" 
    Height="50"> 
    <Rectangle RadiusX="23" RadiusY="23" Fill="SkyBlue" /> 
</Border> 

Sono consapevole che si desidera ritagliare il riempimento di colore del Rectangle, ma si potrebbe utilizzare la proprietà Rectangle.Clip per questo:

<Border CornerRadius="25" BorderBrush="RoyalBlue" BorderThickness="3" Width="300" 
    Height="50"> 
    <Grid> 
     <Rectangle Name="ClipRectangle" Fill="Green" Margin="50,0,0,0" 
      Visibility="Hidden" /> 
     <Rectangle RadiusX="23" RadiusY="23" Fill="SkyBlue" Clip="{Binding 
      RenderedGeometry, ElementName=ClipRectangle}" /> 
    </Grid> 
</Border> 

questa clip colorato Rectangle con l'RenderedGeometry dell'altro Rectangle nome ClipRectangle ... o quando dico questo c labbra, forse avrei dovuto dire questo dovrebbe per clip come ho appena scoperto che questo sembra funzionare solo in WPF Designer e non quando viene eseguita l'applicazione.

enter image description here

Tuttavia, sono fuori tempo qui, quindi speriamo si può trovare il pezzo finale del puzzle e completare da soli. Potenzialmente, è possibile completare questo con il binding dei dati alla proprietà GradientStop.Offset di LinearGradientBrush impostata come Background su Border, quindi non è necessario nemmeno un Rectangle per questo metodo. Avrò un'altra occhiata se posso più tardi.


UPDATE >>>

ho avuto un altro sguardo a questo Clip Rectangle e non può capire perché funziona solo nella progettazione di Visual Studio. Quindi, rinunciando a questa idea, puoi provare l'idea di LinearGradientBrush, che è ugualmente buona.In primo luogo, definire il Brush:

<LinearGradientBrush x:Key="ValueBrush" StartPoint="0,0" EndPoint="1,0"> 
    <GradientStop Offset="0.0" Color="SkyBlue" /> 
    <GradientStop Offset="0.7" Color="SkyBlue" /> 
    <GradientStop Offset="0.7" Color="Transparent" /> 
    <GradientStop Offset="1.0" Color="Transparent" /> 
</LinearGradientBrush> 

Per ora, ho hardcoded i valori per produrre questo:

enter image description here

Da solo questo codice:

<Border CornerRadius="25" BorderBrush="RoyalBlue" Background="{StaticResource 
    ValueBrush}" BorderThickness="3" Width="300" Height="50" ClipToBounds="True" /> 

Per la vostra requisiti effettivi, è necessario creare una proprietà double per associare i dati alla proprietà GradientStop.Offset in questo modo:

<LinearGradientBrush x:Key="ValueBrush" StartPoint="0,0" EndPoint="1,0"> 
    <GradientStop Offset="0.0" Color="SkyBlue" /> 
    <GradientStop Offset="{Binding MidPoint}" Color="SkyBlue" /> 
    <GradientStop Offset="{Binding MidPoint}" Color="Transparent" /> 
    <GradientStop Offset="1.0" Color="Transparent" /> 
</LinearGradientBrush> 

Ora, se si fornisce un valore compreso tra 0.0 e 1.0, questo creerà il misuratore di livello.

+0

questo è esattamente quello che stavo cercando, grazie. lo proverò –

+0

In realtà non riuscivo a farlo funzionare, proverò più tardi +1 min-while –

2

Quello che ho finito per fare:

ControlTemplate:

  <ControlTemplate TargetType="{x:Type ProgressBar}"> 
       <Grid x:Name="TemplateRoot" SnapsToDevicePixels="true"> 

        <Rectangle x:Name="PART_Track" Fill="White" /> 

        <Border x:Name="roundBorder" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="10"/> 

        <Border x:Name="PART_Indicator" HorizontalAlignment="Left"> 

         <Border.Clip> 
          <MultiBinding Converter="{x:Static common:UIConverters.BorderClipConverter}"> 
           <Binding Path="ActualWidth" ElementName="roundBorder" /> 
           <Binding Path="ActualHeight" ElementName="roundBorder" /> 
           <Binding Path="CornerRadius" ElementName="roundBorder" /> 
          </MultiBinding> 
         </Border.Clip> 

         <Grid x:Name="Foreground"> 
          <Rectangle x:Name="Indicator" Fill="{TemplateBinding Background}" /> 
          <Grid x:Name="Animation" ClipToBounds="true"> 
           <Rectangle x:Name="PART_GlowRect" Fill="#FF86C7EB" HorizontalAlignment="Left" Margin="-100,0,0,0" Width="100" /> 
          </Grid> 
         </Grid> 
        </Border> 

       </Grid>    
     </ControlTemplate> 

BorderClipConverter: (da Marat Khasanov answer) con qualche messa a punto nel Rect

public class BorderClipConverter : IMultiValueConverter 
{ 
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 
    { 
     if (values.Length == 3 && values[0] is double && values[1] is double && values[2] is CornerRadius) 
     { 
      var width = (double)values[0]; 
      var height = (double)values[1]; 

      if (width < Double.Epsilon || height < Double.Epsilon) 
      { 
       return Geometry.Empty; 
      } 

      var radius = (CornerRadius)values[2]; 

      var clip = new RectangleGeometry(new Rect(1.5, 1.5, width - 3, height - 3), radius.TopLeft, radius.TopLeft); 
      clip.Freeze(); 

      return clip; 
     } 

     return DependencyProperty.UnsetValue; 
    } 

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) 
    { 
     throw new NotSupportedException(); 
    } 
} 
2

Una soluzione molto migliore con un OpacityMask , Tutte le parti del modello a parte l'OuterBorder inserito in "MainGrid" sono ritagliate usando una maschera Opacity che viene impostata da un oggetto a parte chiamato "MaskBorder".

"TemplateRoot" esiste per il funzionamento interno del controllo PrograssBar.

<ControlTemplate TargetType="{x:Type ProgressBar}"> 
     <Grid x:Name="TemplateRoot"> 
      <Border x:Name="OuterBorder" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="10"> 
       <Grid> 
        <Border x:Name="MaskBorder" Background="{TemplateBinding Background}" CornerRadius="9.5" /> 

        <Grid x:Name="MainGrid"> 
         <Grid.OpacityMask> 
          <VisualBrush Visual="{Binding ElementName=MaskBorder}" />         
         </Grid.OpacityMask> 

         <Rectangle x:Name="PART_Track" Fill="White" /> 

         <Border x:Name="PART_Indicator" HorizontalAlignment="Left">         
          <Grid x:Name="Foreground"> 
           <Rectangle x:Name="Indicator" Fill="{TemplateBinding Background}" /> 
           <Grid x:Name="Animation" ClipToBounds="true"> 
            <Rectangle x:Name="PART_GlowRect" Fill="#FF86C7EB" HorizontalAlignment="Left" Margin="-100,0,0,0" Width="100" /> 
           </Grid> 
          </Grid> 
         </Border>                 
        </Grid>                                  

       </Grid>       
      </Border>      
     </Grid>      
    </ControlTemplate> 
+0

Ciao @ Sheridan, ho trovato una soluzione molto migliore di quella che avevo. –