2015-06-22 5 views
3

Я создаю приложение wpf с настраиваемым элементом управления и все работает до сих пор.
Но теперь я столкнулся с двумя проблемами:Шаблон пользовательского контроля/управления WPF

  1. Я хочу, чтобы назначить цвет фона для моего контроля, но что перекрывает прямоугольник внутри сетки, поэтому прямоугольник становится невидимым.
  2. Я попытался написать шаблон для ContentControl, но контент не отображается как ожидалось, а это означает, что только отображаемое имя отображается с текстом каждого индикатора выполнения.

Шаблон для моего пользовательского элемента управления (если код позади представляет интерес я добавлю, что хорошо):

<Style TargetType="{x:Type local:MetroProgressBar}"> 
    <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="{x:Type local:MetroProgressBar}"> 
       <Grid Background="{TemplateBinding Background}"> 
        <Rectangle Fill="{TemplateBinding ProgressBrush}" HorizontalAlignment="Left" 
           VerticalAlignment="Stretch" Width="{TemplateBinding ProgressBarWidth}" 
           Visibility="{TemplateBinding IsHorizontal, Converter={StaticResource BoolToVis}}"/> 

        <Rectangle Fill="{TemplateBinding ProgressBrush}" HorizontalAlignment="Stretch" 
           VerticalAlignment="Bottom" Height="{TemplateBinding ProgressBarHeight}" 
           Visibility="{TemplateBinding IsVertical, Converter={StaticResource BoolToVis}}"/> 

        <Border 
         Background="{TemplateBinding Background}" 
         BorderBrush="{TemplateBinding BorderBrush}" 
         BorderThickness="{TemplateBinding BorderThickness}"/> 

        <TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" 
           Text="{TemplateBinding Text}" 
           FontSize="{TemplateBinding FontSize}" FontStyle="{TemplateBinding FontStyle}" FontWeight="{TemplateBinding FontWeight}" 
           FontFamily="{TemplateBinding FontFamily}" FontStretch="{TemplateBinding FontStretch}" 
           Foreground="{TemplateBinding Foreground}" TextWrapping="Wrap"/> 

        <Polygon Fill="{TemplateBinding BorderBrush}" Points="{TemplateBinding LeftBorderTriangle}"/> 
        <Polygon Fill="{TemplateBinding BorderBrush}" Points="{TemplateBinding RightBorderTriangle}"/> 
       </Grid> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
</Style> 

Шаблон для ContentControl:

<vm:RamViewModel x:Key="RamInformationSource"/> 

<Style TargetType="ContentControl" x:Key="MemoryUsageTemplate"> 
    <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate> 
       <Grid DataContext="{Binding Source={StaticResource RamInformationSource}}"> 
        <Grid.ColumnDefinitions> 
         <ColumnDefinition Width="*"/> 
         <ColumnDefinition Width="*"/> 
         <ColumnDefinition Width="*"/> 
         <ColumnDefinition Width="*"/> 
        </Grid.ColumnDefinitions> 

        <TextBlock HorizontalAlignment="Center" Text="{Binding DisplayName}" VerticalAlignment="Center" 
           FontSize="15"/> 

        <ctrl:MetroProgressBar Grid.Column="1" VerticalAlignment="Stretch" Width="55" Orientation="Vertical" HorizontalAlignment="Center" 
              ExtenedBorderWidth="0.25" BorderBrush="Gray" Text="Available memory" Progress="{Binding AvailableMemory}" 
              MaxValue="{Binding TotalMemory}"/> 

        <ctrl:MetroProgressBar Grid.Column="2" VerticalAlignment="Stretch" Width="60" Orientation="Vertical" HorizontalAlignment="Center" 
              ExtenedBorderWidth="0.2" BorderBrush="Black" Text="Total memory" Progress="100" 
              MaxValue="{Binding TotalMemory}"/> 

        <ctrl:MetroProgressBar Grid.Column="3" VerticalAlignment="Stretch" Width="60" Orientation="Vertical" HorizontalAlignment="Center" 
              ExtenedBorderWidth="0.2" BorderBrush="DodgerBlue" Text="Used memory" Progress="{Binding UsedMemory}" 
              MaxValue="{Binding TotalMemory}"/> 
       </Grid> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
</Style> 

xaml, который отображает содержание:

... 
<ContentControl Style="{StaticResource MemoryUsageTemplate}"/> 

<ctrl:MetroProgressBar Grid.Row="1" BorderBrush="Black" Text="Test" HorizontalAlignment="Left" Background="Aquamarine" 
         Orientation="Horizontal" BorderThickness="2" Height="50" Width="200" Progress="46"/> 

<ctrl:MetroProgressBar Grid.Row="1" BorderBrush="Black" Text="Test" HorizontalAlignment="Right" 
         Orientation="Horizontal" BorderThickness="2" Height="50" Width="200" Progress="46"/> 
... 

Top: ContentControl with the template applied, left bottom: custom control with background set, right bottom: custom control with no background set

В верхней части изображения показан элемент управления содержимым с нанесенным шаблоном. Нижняя часть показывает два индикатора выполнения, как определено в последнем xaml (слева на фоне, справа без). Это все пользовательские DPs, которые определены для управления:

/// <summary> 
/// Identifies the ExtenedBorderWidth property. 
/// </summary> 
public static readonly DependencyProperty ExtenedBorderWidthProperty = 
    DependencyProperty.Register("ExtenedBorderWidth", typeof(double), typeof(MetroProgressBar), 
            new PropertyMetadata(0.17, ExtendedBorderWidthValueChanged)); 

/// <summary> 
/// Identifies the Text property. 
/// </summary> 
public static readonly DependencyProperty TextProperty = 
    DependencyProperty.Register("Text", typeof(string), typeof(MetroProgressBar), new PropertyMetadata("")); 

/// <summary> 
/// Identifies the Orientation property. 
/// </summary> 
public static readonly DependencyProperty OrientationProperty = 
    DependencyProperty.Register("Orientation", typeof(Orientation), typeof(MetroProgressBar), new PropertyMetadata(Orientation.Horizontal, OrientationValueChanged)); 

/// <summary> 
/// Identifies the IsHorizontal property. 
/// </summary> 
public static readonly DependencyProperty IsHorizontalProperty = 
    DependencyProperty.Register("IsHorizontal", typeof(bool), typeof(MetroProgressBar), new PropertyMetadata(true, OrientationChangedByProperty)); 

/// <summary> 
/// Identifies the IsVertical property. 
/// </summary> 
public static readonly DependencyProperty IsVerticalProperty = 
    DependencyProperty.Register("IsVertical", typeof(bool), typeof(MetroProgressBar), new PropertyMetadata(false, OrientationChangedByProperty)); 

/// <summary> 
/// Identifies the ProgressBrush property. 
/// </summary> 
public static readonly DependencyProperty ProgressBrushProperty = 
    DependencyProperty.Register("ProgressBrush", typeof(Brush), typeof(MetroProgressBar), new PropertyMetadata(new SolidColorBrush(Colors.LightGreen))); 

/// <summary> 
/// Identifies the LeftBorderTriangle property. 
/// </summary> 
public static readonly DependencyProperty LeftBorderTriangleProperty = 
    DependencyProperty.Register("LeftBorderTriangle", typeof(PointCollection), typeof(MetroProgressBar), new PropertyMetadata(new PointCollection())); 

/// <summary> 
/// Identifies the RightBorderTriangle property. 
/// </summary> 
public static readonly DependencyProperty RightBorderTriangleProperty = 
    DependencyProperty.Register("RightBorderTriangle", typeof(PointCollection), typeof(MetroProgressBar), new PropertyMetadata(new PointCollection())); 

/// <summary> 
/// Identifies the MaxValue property. 
/// </summary> 
public static readonly DependencyProperty MaxValueProperty = 
    DependencyProperty.Register("MaxValue", typeof(ulong), typeof(MetroProgressBar), new PropertyMetadata(100UL, MaxValueChanged)); 

/// <summary> 
/// Identifies the Progress property. 
/// </summary> 
public static readonly DependencyProperty ProgressProperty = 
    DependencyProperty.Register("Progress", typeof(double), typeof(MetroProgressBar), new PropertyMetadata(0.0d, ProgressValueChanged)); 

/// <summary> 
/// Identifies the ProgressBarWidth property. 
/// </summary> 
public static readonly DependencyProperty ProgressBarWidthProperty 
    = DependencyProperty.Register("ProgressBarWidth", typeof(double), typeof(MetroProgressBar), new PropertyMetadata(0.0d)); 

/// <summary> 
/// Identifies the ProgressBarHeight property. 
/// </summary> 
public static readonly DependencyProperty ProgressBarHeightProperty 
    = DependencyProperty.Register("ProgressBarHeight", typeof(double), typeof(MetroProgressBar), new PropertyMetadata(0.0d)); 

Значения DP изменилось обратные вызовы и методы экземпляра:

#region Static 

/// <summary> 
/// Changes the orientation based on the calling property. 
/// </summary> 
/// <param name="source">The source of the event.</param> 
/// <param name="e">Event information.</param> 
private static void OrientationChangedByProperty(DependencyObject source, DependencyPropertyChangedEventArgs e) 
{ 
    //lock (lockOrientationByProperty) 
    { 
     MetroProgressBar pb = source as MetroProgressBar; 

     if (e.Property == IsVerticalProperty) 
     { 
      if ((bool)e.NewValue) 
      { 
       pb.IsHorizontal = false; 
       pb.Orientation = Orientation.Vertical; 
      } 
      else 
      { 
       pb.IsHorizontal = true; 
       pb.Orientation = Orientation.Horizontal; 
      } 
     } 
     else 
     { 
      // IsVerticalProperty is property that changed 
      if (!(bool)e.NewValue) 
      { 
       pb.IsHorizontal = false; 
       pb.Orientation = Orientation.Vertical; 
      } 
      else 
      { 
       pb.IsHorizontal = true; 
       pb.Orientation = Orientation.Horizontal; 
      } 
     } 

     AdjustVisibleProgressRect(pb); 
    } 
} 

/// <summary> 
/// Sets the progress value to the new maximum value, if the new max value is less than 
/// the current progress value. 
/// </summary> 
/// <param name="source">The source of the event.</param> 
/// <param name="e">Event information.</param> 
private static void MaxValueChanged(DependencyObject source, DependencyPropertyChangedEventArgs e) 
{ 
    //lock (lockMaxValue) 
    { 
     MetroProgressBar pb = source as MetroProgressBar; 

     ulong val = Convert.ToUInt64(e.NewValue); 
     if (val < Convert.ToUInt64(pb.Progress)) 
     { 
      pb.Progress = val; 

      // Raise finished event 
      pb.OnFinished(EventArgs.Empty); 
     } 
    } 
} 

/// <summary> 
/// Changes the width of the progress indication rectangle of the progress bar. 
/// </summary> 
/// <param name="source">The source of the event.</param> 
/// <param name="e">Event information.</param> 
private static void ProgressValueChanged(DependencyObject source, DependencyPropertyChangedEventArgs e) 
{ 
    //lock (lockProgress) 
    { 
     MetroProgressBar pb = source as MetroProgressBar; 
     AdjustVisibleProgressRect(pb, (double)e.NewValue); 

     pb.OnProgressChanged(new ProgressChangedEventArgs((double)e.NewValue)); 

     // If new progress value equals or is greater than max value raise the finished event 
     if (pb.MaxValue <= Convert.ToUInt64(e.NewValue)) 
      pb.OnFinished(EventArgs.Empty); 
    } 
} 

/// <summary> 
/// Changes the width of the progress indication rectangle of the progress bar. 
/// </summary> 
/// <param name="sender">The source of the event.</param> 
/// <param name="e">Event information.</param> 
private static void OrientationValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) 
{ 
    //lock (lockOrientation) 
    { 
     MetroProgressBar pb = sender as MetroProgressBar; 
     pb.AdjustToOrientationChange(); 

     if (pb.Orientation == Orientation.Horizontal) 
     { 
      pb.IsVertical = false; 
      pb.IsHorizontal = true; 
     } 
     else 
     { 
      pb.IsVertical = true; 
      pb.IsHorizontal = false; 
     } 

     pb.OnOrientationChanged(new OrientationChangedEventArgs((Orientation)e.OldValue, (Orientation)e.NewValue)); 
    } 
} 

/// <summary> 
/// Causes the progress bar to reassign the extended border. 
/// </summary> 
/// <param name="sender">The source of the event.</param> 
/// <param name="e">Event information.</param> 
private static void ExtendedBorderWidthValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) 
{ 
    //lock (lockExtendedBorder) 
    { 
     MetroProgressBar pb = sender as MetroProgressBar; 
     pb.SetUpBorderParts(); 
    } 
} 

/// <summary> 
/// Adjusts the progress bars visible progress rectangles after progress or visible changes. 
/// </summary> 
/// <param name="pb">The progress bar that changed.</param> 
/// <param name="newValue">The new progress value. Only has to be set if there has been a progress change.</param> 
private static void AdjustVisibleProgressRect(MetroProgressBar pb, double newValue = -1) 
{ 
    if (pb.Orientation == Orientation.Horizontal) 
    { 
     pb.ProgressBarWidth = (newValue == -1 ? pb.Progress : newValue)/pb.MaxValue * pb.Width; 
    } 
    else 
    { 
     pb.ProgressBarHeight = (newValue == -1 ? pb.Progress : newValue)/pb.MaxValue * pb.Height; 
    } 
} 

#endregion 

#region Non-Static 

/// <summary> 
/// Adjusts the border ornaments to the new orientation of the control. 
/// </summary> 
private void AdjustToOrientationChange() 
{ 
    SetUpBorderParts(); 
} 

/// <summary> 
/// Sets up the triangles that are placed on the left and right side of the progress bar. 
/// </summary> 
private void SetUpBorderParts() 
{ 
    PointCollection leftBorder = new PointCollection(); 
    PointCollection rightBorder = new PointCollection(); 

    double borderWidth = ExtenedBorderWidth; 

    if (Orientation == Orientation.Horizontal) 
    { 
     // Left triangle 
     leftBorder.Add(new Point(0, 0)); 
     leftBorder.Add(new Point(0, Height)); 
     leftBorder.Add(new Point(Width * borderWidth, 0)); 

     // Right triangle 
     rightBorder.Add(new Point(Width, 0)); 
     rightBorder.Add(new Point(Width, Height)); 
     rightBorder.Add(new Point(Width - (Width * borderWidth), Height)); 
    } 
    else 
    { 
     // Top border 
     leftBorder.Add(new Point(0, 0)); 
     leftBorder.Add(new Point(Width, 0)); 
     leftBorder.Add(new Point(0, Height * borderWidth)); 

     // Bottom border 
     rightBorder.Add(new Point(0, Height)); 
     rightBorder.Add(new Point(Width, Height)); 
     rightBorder.Add(new Point(Width, Height - (Height * borderWidth))); 
    } 

    LeftBorderTriangle = leftBorder; 
    RightBorderTriangle = rightBorder; 
} 

/// <summary> 
/// Raises the Fnished event. 
/// </summary> 
/// <param name="e">Information on the event.</param> 
protected virtual void OnFinished(EventArgs e) 
{ 
    EventHandler handler = finished; 

    if (handler != null) 
    { 
     handler(this, e); 
    } 
} 

/// <summary> 
/// Raises the ProgressChanged event. 
/// </summary> 
/// <param name="e">Information on the event.</param> 
protected virtual void OnProgressChanged(ProgressChangedEventArgs e) 
{ 
    EventHandler<ProgressChangedEventArgs> handler = progressChanged; 

    if (handler != null) 
    { 
     handler(this, e); 
    } 
} 

/// <summary> 
/// Raises the OrientationChanged event. 
/// </summary> 
/// <param name="e">Information on the event.</param> 
protected virtual void OnOrientationChanged(OrientationChangedEventArgs e) 
{ 
    EventHandler<OrientationChangedEventArgs> handler = orientationChanged; 

    if (handler != null) 
    { 
     handler(this, e); 
    } 
} 

/// <summary> 
/// Raises the RenderSizeChanged event and sets up the border parts. 
/// </summary> 
/// <param name="sizeInfo">Info on the size change.</param> 
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo) 
{ 
    base.OnRenderSizeChanged(sizeInfo); 
    SetUpBorderParts(); 
    AdjustVisibleProgressRect(this); 
} 

#endregion 
+0

Я запутался в двух «MetroProgressBa'r в' 'как вы различаете эти два стиля? –

+2

Скриншот приятно видеть для таких проблем. Проблема заключается в том, что у вас больше свойств зависимостей, чем у одного «фона», например. 'AnotherBackground'? – Sinatr

+0

@Sinatr Я хотел включить скриншот, но не имею достаточной репутации, чтобы включить его ... – Streamline

ответ

0

я нашел ответ на мою первую проблему ... В принципе Border элемент индикатора выполнения имел свое фоновое свойство, связанное с фоном управления, и поскольку оно находится после прямоугольника в визуальном дереве, оно перекрывало их оба.

Вторая проблема возникла потому, что я использовал Height и Width вместо ActualHeight и ActualWidth в коде пользовательского элемента управления. Поэтому при работе с, например, HorizontalAlignment.Stretch Свойства Width/Height не установлены, и поэтому все расчеты на их основе не работают.

Смежные вопросы