2011-10-07 19 views
24

是否有一種在WPF中實現此類控件的最佳方式?在WPF中實現嚮導進度控制

Wizard Progress Control

我可以很容易複製的文本標籤和進度條(無每個標籤上面的圓形「顛簸」),但我想知道,如果已經有一個控制在那裏,或最佳實踐,用於在WPF中創建這種控制。

+0

我不認爲現在有什麼特別的東西。我猜你想要標籤和百分比是動態的嗎? – Stimul8d

+0

優選地。我想能夠放入一個'ItemsControl'(或其他列表)的標籤,並選擇一個當前的步驟或索引,但我打開其他選項。 –

回答

63

很難說什麼最佳實踐是在這種情況下,但這裏是我如何做到這一點。

在你的屏幕截圖嚮導控制看起來像一個ProgressBar的組合和ItemsControl,在這種情況下,它似乎更容易把我從ItemsControl推導和實施進度功能,那麼周圍的其他方式,但它也取決於你如何希望它的工作(如果你想順利進行或者只是照亮了點一個接一個的例子)

使用UniformGridItemsPanel及以下ItemTemplate,我們得到如下的樣子(步驟是一個字符串List
enter image description here

<ItemsControl ItemsSource="{Binding Steps}"> 
    <ItemsControl.ItemsPanel> 
     <ItemsPanelTemplate> 
      <UniformGrid Rows="1"/> 
     </ItemsPanelTemplate> 
    </ItemsControl.ItemsPanel> 
    <ItemsControl.ItemTemplate> 
     <DataTemplate> 
      <Grid> 
       <Grid.RowDefinitions> 
        <RowDefinition Height="Auto"/> 
        <RowDefinition Height="Auto"/> 
       </Grid.RowDefinitions> 
       <Ellipse HorizontalAlignment="Center" Height="20" Width="20" Stroke="Transparent" Fill="Blue"/> 
       <TextBlock Grid.Row="1" Text="{Binding}" HorizontalAlignment="Center" Margin="0,5,0,0"/> 
      </Grid> 
     </DataTemplate> 
    </ItemsControl.ItemTemplate> 
</ItemsControl> 

添加DropShadowEffectItemsPanel,二Path元素ItemTemplate和兩個DataTriggers來確定當前項目是否顯示/隱藏左/右的第一個或最後一個項目,我們可以得到一個非常相似的外觀到您的截圖
enter image description here

ItemsPanel

<UniformGrid Rows="1" SnapsToDevicePixels="True"> 
    <UniformGrid.Effect> 
     <DropShadowEffect Color="Black" 
          BlurRadius="5" 
          Opacity="0.6" 
          ShadowDepth="0"/> 
    </UniformGrid.Effect> 
</UniformGrid> 

的ItemTemplate

<DataTemplate> 
    <DataTemplate.Resources> 
     <Style TargetType="Path"> 
      <Setter Property="Data" Value="M0.0,0.0 L0.0,0.33 L1.0,0.33 L1.0,0.66 L0.0,0.66 L0.0,1.0"/> 
      <Setter Property="StrokeThickness" Value="0"/> 
      <Setter Property="Height" Value="21"/> 
      <Setter Property="Stretch" Value="Fill"/> 
      <Setter Property="Fill" Value="{StaticResource wizardBarBrush}"/> 
      <Setter Property="StrokeEndLineCap" Value="Square"/> 
      <Setter Property="StrokeStartLineCap" Value="Square"/> 
      <Setter Property="Stroke" Value="Transparent"/> 
     </Style> 
    </DataTemplate.Resources> 
    <Grid> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="Auto"/> 
      <RowDefinition Height="Auto"/> 
     </Grid.RowDefinitions> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition/> 
      <ColumnDefinition/> 
     </Grid.ColumnDefinitions> 
     <Path Name="leftPath"/> 
     <Path Name="rightPath" Grid.Column="1"/> 
     <Ellipse Grid.ColumnSpan="2" HorizontalAlignment="Center" Height="20" Width="20" Stroke="Transparent" Fill="{StaticResource wizardBarBrush}"/> 
     <TextBlock Grid.ColumnSpan="2" Grid.Row="1" Text="{Binding}" HorizontalAlignment="Center" Margin="0,5,0,0"/> 
    </Grid> 
    <DataTemplate.Triggers> 
     <DataTrigger Binding="{Binding RelativeSource={RelativeSource PreviousData}}" 
        Value="{x:Null}"> 
      <Setter TargetName="leftPath" Property="Visibility" Value="Collapsed"/> 
     </DataTrigger> 
     <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Converter={markup:IsLastItemConverter}}" 
        Value="True"> 
      <Setter TargetName="rightPath" Property="Visibility" Value="Collapsed"/> 
     </DataTrigger> 
    </DataTemplate.Triggers> 
</DataTemplate> 

如果你決定使用這種方法,你也許可以鍛鍊如何讓剩下的去,如

  • 在可重複使用自定義的控制實現此
  • 只有獲得進展,部分行程(DropShadowEffect),而不是在文本
  • 反正落實進度功能等

,我上傳了一個名爲WizardProgressBar的自定義控件示例項目和一個演示項目:https://www.dropbox.com/s/ng9vfi6uwn1peot/WizardProgressBarDemo2.zip?dl=0

看起來像這樣
enter image description here

事情需要注意樣品

  • 我的情況下結束了,我會得到的進展,部分DropShadowEffect和標題或獲得各項目之間的細線(如中所看到的圖片)。我想不出一個簡單的方法來擺脫它,所以也許這畢竟不是最好的辦法:)
  • 進度部分很簡單。它只是在0-100之間的一個值,然後轉換器決定是否應該點亮該項目
  • 該控件可能會有一個小的性能影響,但我不能確定,因爲我的電腦似乎今天運行緩慢..

更新

作出哪裏分裂呈現爲兩個ItemsControls擺脫各個項目之間的細線的樣本項目中的一些變化。現在看起來像這樣
enter image description here
上傳在這裏:更新

https://www.dropbox.com/s/ng9vfi6uwn1peot/WizardProgressBarDemo2.zip?dl=0

結束,並在這裏是上述

<LinearGradientBrush x:Key="wizardBarBrush" StartPoint="0.5,0.0" EndPoint="0.5,1.0"> 
    <GradientStop Color="#FFE4E4E4" Offset="0.25"/> 
    <GradientStop Color="#FFededed" Offset="0.50"/> 
    <GradientStop Color="#FFFCFCFC" Offset="0.75"/> 
</LinearGradientBrush> 

IsLastItemConverter

從示例代碼中缺少的部分
public class IsLastItemConverter : MarkupExtension, IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     ContentPresenter contentPresenter = value as ContentPresenter; 
     ItemsControl itemsControl = ItemsControl.ItemsControlFromItemContainer(contentPresenter); 
     int index = itemsControl.ItemContainerGenerator.IndexFromContainer(contentPresenter); 
     return (index == (itemsControl.Items.Count - 1)); 
    } 
    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     throw new NotSupportedException(); 
    } 

    public IsLastItemConverter() { } 
    public override object ProvideValue(IServiceProvider serviceProvider) 
    { 
     return this; 
    } 
} 
+5

令人難以置信,完全徹底的答案。你應該得到這個職位的兩倍賞金。謝謝! –

+0

謝謝亞當:)我對示例項目做了一些改變,擺脫了每個項目之間的細線。 –

+1

+1,做得好! –

2

我也做過類似的事情。在WPF中它實際上相當簡單。基本上我創建了2個矩形並重疊它們。背景中的矩形具有漸變顏色,前景中的矩形是用於遮蓋漸變矩形的灰色區域。

只需調整灰色矩形的寬度即可讓小節向右或向左移動。

下面是我做的,以及XAML的圖像。

enter image description here

<Border BorderThickness="2" BorderBrush="Black" CornerRadius="2"> 
    <Canvas x:Name="canvasMain" Height="80" Width="330" VerticalAlignment="Top" Background="White" SnapsToDevicePixels="True"> 

     <Rectangle x:Name="recMainBar" Height="30" Canvas.Left="0" Canvas.Top="30" Stroke="Black" Width="300"> 
      <Rectangle.Fill> 
       <LinearGradientBrush EndPoint="1,1" MappingMode="RelativeToBoundingBox" StartPoint="0,0" SpreadMethod="Reflect"> 
        <GradientStop Color="#FFF5400A"/> 
        <GradientStop Color="#FF54C816" Offset="1"/> 
        <GradientStop Color="#FF31C614" Offset="0.996"/> 
       </LinearGradientBrush> 
      </Rectangle.Fill> 
     </Rectangle> 

     <!-- Cover of the bar --> 
     <Rectangle x:Name="recMainBarCover" Height="30" Canvas.Top="30" Canvas.Left="0" Stroke="Black" Width="300" Fill="#FFEBEBEB"/> 

     <Path Data="M8,34 L24.5,48.95" Fill="Green" Height="6.95" Stretch="Fill" Stroke="Black" Canvas.Top="60" Width="5"/> 
     <TextBlock FontSize="10" Height="15" Canvas.Left="2.0" TextWrapping="Wrap" Text="0%" Canvas.Top="66.95" Width="16" RenderTransformOrigin="-0.051,-0.9"/> 

     <Path Data="M8,34 L24.5,48.95" Fill="Green" Height="6.95" Stretch="Fill" Stroke="Black" Canvas.Left="30" Canvas.Top="60" Width="5"/> 
     <TextBlock FontSize="10" Height="15" Canvas.Left="30" Text="10%" Canvas.Top="66.95" Width="21" RenderTransformOrigin="-0.051,-0.9"/> 

     <Path Data="M8,34 L24.5,48.95" Fill="Green" Height="6.95" Stretch="Fill" Stroke="Black" Canvas.Left="60" Canvas.Top="60" Width="5"/> 
     <TextBlock FontSize="10" Height="15" Canvas.Left="60" Text="20%" Canvas.Top="66.95" Width="21" RenderTransformOrigin="-0.051,-0.9"/> 

     <Path Data="M8,34 L24.5,48.95" Fill="Green" Height="6.95" Stretch="Fill" Stroke="Black" Canvas.Left="90" Canvas.Top="60" Width="5"/> 
     <TextBlock FontSize="10" Height="15" Canvas.Left="90" Text="30%" Canvas.Top="66.95" Width="21" RenderTransformOrigin="-0.051,-0.9"/> 

     <Path Data="M8,34 L24.5,48.95" Fill="Green" Height="6.95" Stretch="Fill" Stroke="Black" Canvas.Left="120" Canvas.Top="60" Width="5"/> 
     <TextBlock FontSize="10" Height="15" Canvas.Left="120" Text="40%" Canvas.Top="66.95" Width="21" RenderTransformOrigin="-0.051,-0.9"/> 

     <Path Data="M8,34 L24.5,48.95" Fill="Green" Height="6.95" Stretch="Fill" Stroke="Black" Canvas.Left="150" Canvas.Top="60" Width="5"/> 
     <TextBlock FontSize="10" Height="15" Canvas.Left="145" FontWeight="Bold" Text="50%" Canvas.Top="66.95" Width="31" RenderTransformOrigin="-0.051,-0.9"/> 

     <Path Data="M8,34 L24.5,48.95" Fill="Green" Height="6.95" Stretch="Fill" Stroke="Black" Canvas.Left="180" Canvas.Top="60" Width="5"/> 
     <TextBlock FontSize="10" Height="15" Canvas.Left="180" Text="60%" Canvas.Top="66.95" Width="27" RenderTransformOrigin="-0.051,-0.9"/> 

     <Path Data="M8,34 L24.5,48.95" Fill="Green" Height="6.95" Stretch="Fill" Stroke="Black" Canvas.Left="210" Canvas.Top="60" Width="5"/> 
     <TextBlock FontSize="10" Height="15" Canvas.Left="210" Text="70%" Canvas.Top="66.95" Width="27" RenderTransformOrigin="-0.051,-0.9"/> 

     <Path Data="M8,34 L24.5,48.95" Fill="Green" Height="6.95" Stretch="Fill" Stroke="Black" Canvas.Left="240" Canvas.Top="60" Width="5"/> 
     <TextBlock FontSize="10" Height="15" Canvas.Left="240" Text="80%" Canvas.Top="66.95" Width="27" RenderTransformOrigin="-0.051,-0.9"/> 

     <Path Data="M8,34 L24.5,48.95" Fill="Green" Height="6.95" Stretch="Fill" Stroke="Black" Canvas.Left="270" Canvas.Top="60" Width="5"/> 
     <TextBlock FontSize="10" Height="15" Canvas.Left="270" Text="90%" Canvas.Top="66.95" Width="27" RenderTransformOrigin="-0.051,-0.9"/> 

     <Path Data="M8,34 L24.5,48.95" Fill="Green" Height="6.95" Stretch="Fill" Stroke="Black" Canvas.Left="300" Canvas.Top="60" Width="5"/> 
     <TextBlock FontSize="10" Height="15" Canvas.Left="300" Text="100%" Canvas.Top="66.95" Width="27" RenderTransformOrigin="-0.051,-0.9"/> 

     <TextBlock Name="txtTitle" FontSize="16" FontWeight="Bold" Background="Black" Foreground="White" Height="30" Canvas.Left="0" Text="Confidence Factor" Canvas.Top="0" Width="330" HorizontalAlignment="Center" TextAlignment="Center"/> 

    </Canvas> 
</Border> 
+1

正如我所說的,重新創建文本標籤和進度(沒有在每個標籤上碰撞)很容易。我期待完全複製我發佈爲可重用控件的設計。 –

0

你可以繪製完整的進度指示器,建立進度指示器剪貼蒙版,並且無論是改變或與程序的執行過程中,在適當的點的另一個面具掩蓋掉。如果你想得到真正的創意,你可以制定一個控制,可以定義任意數量的點。

本文告訴您有關通用剪貼蒙版中表達:http://expression.microsoft.com/en-us/cc197119

本文將向您展示一些代碼,可能會多一點有關: http://blog.pixelingene.com/2009/02/animating-graphs-in-wpf-using-clipping-masks/ 並在此代碼,你可以輕鬆地調整運行時的RectangleGeometry 。

所以我從所有這些閱讀和琢磨明白的是,你可能嘗試在你的藍色進度指示器剪輯屬性,並保留背景原樣。

這是我可能採取的路線。希望這可以幫助!