2013-03-05 33 views
8
  • Cuộn ngang
  • Điều khiển cảm ứng.
  • Mặt hàng chảy xuống, sau đó vào cột tiếp theo
  • Chạm vào một mục sẽ cuộn bảng đến điểm đã đặt để chế độ xem chi tiết luôn ở cùng một vị trí.
  • Cột tiếp theo sẽ "ngắt" và động ở bên phải, để hiển thị ngăn chi tiết trong ngữ cảnh của mục đã chọn.
  • Chạm vào bất kỳ mục hiển thị nào (trong một cột khác) sẽ "đóng" chi tiết đã được tiết lộ, sau đó làm động mục được chọn mới tới điểm tĩnh bên trái và lại cắt cột tiếp theo để hiển thị chi tiết. Chạm vào bất kỳ mục hiển thị nào trong cùng một cột sẽ chỉ thực hiện hoạt ảnh mờ dần.

Dưới đây là một số mocks đơn giản:Một WrapPanel trong đó lựa chọn chia bảng để hiển thị một cái nhìn chi tiết?

90% trong số này là đơn giản đối với tôi, nhưng quá trình để tạo ra một bảng điều khiển bọc mà có thể "riêng biệt" bản thân để tiết lộ một món đồ đang lảng tránh tôi theo một cách lớn. Lời khuyên nào sẽ được đánh giá cao.

+0

Ý tưởng tuyệt vời! Tôi nghĩ rằng Infragistics có một cái gì đó như thế –

+0

Cảm ơn @HighCore. Tải xuống bản dùng thử của Infragistic để xem bạn có thể tham khảo điều khiển nào. – erodewald

Trả lời

2

Một trong những giải pháp là:

Bạn có thể tách rời các nút bên bảng điều khiển bọc (mà là bên trong lưới) bằng cách thay đổi biên độ của một số trong số họ (tất nhiên bạn cần thay đổi kích thước của cửa sổ cũng như nếu bạn muốn giữ kích thước nút và tránh di chuyển chúng sang dòng tiếp theo).

Ví dụ, nếu bạn có 4 cột và ba hàng nút tên nút 1,2,3 vv ... nút khi nút từ cột đầu tiên được nhấp 2,6,10 nhận:

new thickness(space,0,0,0); 

Điều này di chuyển tất cả các nút bên phải bằng giá trị của không gian biến;

Và sau đó

window.width += space; 

Rồi TextBox đó là con của lưới điện là để xác định vị trí ở vị trí phù hợp với không gian rộng.

On undo

 new thickness(0,0,0,0); 

     window.width -= space; 

Nó làm việc cho tôi tốt nhưng tôi tò mò cho các giải pháp khác.

+0

Thú vị, tuy nhiên tôi không chắc chắn nếu bạn đang nói tôi nên thay đổi chiều rộng cửa sổ chrome của tôi hay không. Trong trường hợp của tôi, đó không phải là một lựa chọn khả thi. – erodewald

+0

Yea, theo kích thước cửa sổ tôi có nghĩa là kích thước của bảng điều khiển bọc và lưới (cửa sổ trong một số trường hợp), không có điều này là đơn giản mặc dù tại một số điểm khá ngây thơ cách để đạt được điều đó. – Arek

2

Điều này nghe có vẻ giống như một nhiệm vụ thú vị, vì vậy tôi đã quyết định thực hiện điều gì đó dọc theo những gì bạn muốn. Tôi nghĩ rằng tôi có thể chia sẻ nó để bạn có thể cải thiện nó hoặc sử dụng nó theo ý thích của bạn. Trước hết, nhiệm vụ này vượt quá khả năng triển khai của tôi trong chỉ XAML. Tôi không nói rằng nó không thể được thực hiện, chỉ là nó là một chút khó khăn. Thay vào đó, tôi đã triển khai loại Bảng điều khiển của riêng mình (được gọi là GapPanel). Điều này nghe có vẻ tồi tệ hơn, nhưng có một vài điều tốt đẹp về nó, tuy nhiên, giống như khả năng thực hiện RoutedEvent s để trả lời trong XAML cho hoạt ảnh.

Vì vậy, đây là tải mã.Đầu tiên là XAML

<Window x:Class="SlidingWrapPanel.SecondAttempt" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:local="clr-namespace:SlidingWrapPanel" 
     Title="Wrapped items with details pane" Height="250" Width="600"> 
    <Window.Resources> 
     <ControlTemplate TargetType="Button" x:Key="ItemButtonTemplate"> 
      <ControlTemplate.Triggers> 
       <Trigger Property="IsMouseOver" Value="True"> 
        <Trigger.EnterActions> 
         <BeginStoryboard> 
          <Storyboard> 
           <ColorAnimation Storyboard.TargetName="ButtonBorder" 
              Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" 
              To="#999999" Duration="0:0:0.5" /> 
          </Storyboard> 
         </BeginStoryboard> 
        </Trigger.EnterActions> 
        <Trigger.ExitActions> 
         <BeginStoryboard> 
          <Storyboard> 
           <ColorAnimation Storyboard.TargetName="ButtonBorder" 
              Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" 
              To="#3e3e3e" Duration="0:0:0.5" /> 
          </Storyboard> 
         </BeginStoryboard> 
        </Trigger.ExitActions> 
       </Trigger> 
      </ControlTemplate.Triggers> 
      <Border x:Name="ButtonBorder" Background="#3e3e3e" BorderBrush="#222" BorderThickness="1"> 
       <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Content="{TemplateBinding Content}" Margin="0" /> 
      </Border> 
     </ControlTemplate> 
     <Style x:Key="ItemGridStyle" TargetType="{x:Type Grid}"> 
      <Setter Property="Background" Value="#3e3e3e"/> 
      <Setter Property="Width" Value="150"/> 
      <Setter Property="Height" Value="100"/> 
      <Setter Property="Margin" Value="1"/> 
     </Style> 
     <Style x:Key="ItemButtonStyle" TargetType="{x:Type Button}"> 
      <Setter Property="Foreground" Value="White"/> 
      <Setter Property="HorizontalContentAlignment" Value="Center"/> 
      <Setter Property="VerticalContentAlignment" Value="Center"/> 
      <Setter Property="Template"> 
       <Setter.Value> 
        <Binding Source="{StaticResource ItemButtonTemplate}"/> 
       </Setter.Value> 
      </Setter> 
     </Style> 
     <Style x:Key="DetailsGridStyle" TargetType="{x:Type Grid}"> 
      <Setter Property="Background" Value="#3e3e3e"/> 
      <Setter Property="Width" Value="160"/> 
      <Setter Property="HorizontalAlignment" Value="Left"/> 
      <Setter Property="RenderTransform"> 
       <Setter.Value> 
        <TranslateTransform X="-160" /> 
       </Setter.Value> 
      </Setter> 
     </Style> 
     <Style x:Key="DetailsTextStyle" TargetType="{x:Type TextBlock}"> 
      <Setter Property="Foreground" Value="White"/> 
      <Setter Property="FontFamily" Value="Segoe WP Light"/> 
      <Setter Property="Margin" Value="15"/> 
     </Style> 
     <Storyboard x:Key="ExpandColumnAnimation"> 
      <DoubleAnimation Storyboard.TargetProperty="GapWidth" Storyboard.TargetName="ItemsPanel" 
          From="0" To="{Binding ActualWidth, ElementName=DetailsPanel}" Duration="0:0:0.75"> 
       <DoubleAnimation.EasingFunction> 
        <QuinticEase EasingMode="EaseOut"/> 
       </DoubleAnimation.EasingFunction> 
      </DoubleAnimation> 
      <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)" 
              Storyboard.TargetName="DetailsPanel"> 
       <DiscreteDoubleKeyFrame KeyTime="0" Value="{Binding GapX, ElementName=ItemsPanel}"/> 
      </DoubleAnimationUsingKeyFrames> 
     </Storyboard> 
     <Storyboard x:Key="CollapseColumnAnimation"> 
      <DoubleAnimation Storyboard.TargetProperty="GapWidth" Storyboard.TargetName="ItemsPanel" 
          To="0" Duration="0:0:0.5"> 
       <DoubleAnimation.EasingFunction> 
        <QuinticEase EasingMode="EaseIn"/> 
       </DoubleAnimation.EasingFunction> 
      </DoubleAnimation> 
      <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)" 
              Storyboard.TargetName="DetailsPanel"> 
       <DiscreteDoubleKeyFrame KeyTime="0:0:0.5" Value="-160"/> 
      </DoubleAnimationUsingKeyFrames> 
     </Storyboard> 
    </Window.Resources> 
    <Grid> 
     <Grid> 
      <Grid x:Name="DetailsPanel" Style="{StaticResource DetailsGridStyle}"> 
       <ScrollViewer> 
        <TextBlock Style="{StaticResource DetailsTextStyle}"> 
         <Run Text="Details" FontSize="18"/> 
         <LineBreak /> 
         <Run Text="Some text"/> 
        </TextBlock> 
       </ScrollViewer> 
      </Grid> 
     </Grid> 
     <local:GapPanel x:Name="ItemsPanel"> 
      <local:GapPanel.Triggers> 
       <EventTrigger RoutedEvent="local:GapPanel.ColumnChanged"> 
        <BeginStoryboard Storyboard="{StaticResource ExpandColumnAnimation}"/> 
       </EventTrigger> 
       <EventTrigger RoutedEvent="local:GapPanel.CloseGap"> 
        <BeginStoryboard Storyboard="{StaticResource CollapseColumnAnimation}"/> 
       </EventTrigger> 
      </local:GapPanel.Triggers> 
      <Grid Style="{StaticResource ItemGridStyle}"> 
       <Button Style="{StaticResource ItemButtonStyle}" Content="Item 1" /> 
      </Grid> 
      <Grid Style="{StaticResource ItemGridStyle}"> 
       <Button Style="{StaticResource ItemButtonStyle}" Content="Item 2" /> 
      </Grid> 
      <Grid Style="{StaticResource ItemGridStyle}"> 
       <Button Style="{StaticResource ItemButtonStyle}" Content="Item 3" /> 
      </Grid> 
      <Grid Style="{StaticResource ItemGridStyle}"> 
       <Button Style="{StaticResource ItemButtonStyle}" Content="Item 4"/> 
      </Grid> 
      <Grid Style="{StaticResource ItemGridStyle}"> 
       <Button Style="{StaticResource ItemButtonStyle}" Content="Item 5"/> 
      </Grid> 
      <Grid Style="{StaticResource ItemGridStyle}"> 
       <Button Style="{StaticResource ItemButtonStyle}" Content="Item 6"/> 
      </Grid> 
      <Grid Style="{StaticResource ItemGridStyle}"> 
       <Button Style="{StaticResource ItemButtonStyle}" Content="Item 7"/> 
      </Grid> 
      <Grid Style="{StaticResource ItemGridStyle}"> 
       <Button Style="{StaticResource ItemButtonStyle}" Content="Item 8"/> 
      </Grid> 
      <Grid Style="{StaticResource ItemGridStyle}"> 
       <Button Style="{StaticResource ItemButtonStyle}" Content="Item 9"/> 
      </Grid> 
      <Grid Style="{StaticResource ItemGridStyle}"> 
       <Button Style="{StaticResource ItemButtonStyle}" Content="Item 10"/> 
      </Grid> 
      <Grid Style="{StaticResource ItemGridStyle}"> 
       <Button Style="{StaticResource ItemButtonStyle}" Content="Item 11"/> 
      </Grid> 
      <Grid Style="{StaticResource ItemGridStyle}"> 
       <Button Style="{StaticResource ItemButtonStyle}" Content="Item 12"/> 
      </Grid> 
     </local:GapPanel> 
    </Grid> 
</Window> 

Và (kinh tởm) của một bảng điều khiển ..

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Input; 

namespace SlidingWrapPanel { 
    public class GapPanel : Panel, INotifyPropertyChanged { 
     private readonly IDictionary<UIElement, int> columns; 
     private readonly IDictionary<int, double> gapCoordinates; 
     private object opened; 

     public static readonly DependencyProperty GapColumnProperty = 
      DependencyProperty.Register("GapColumn", typeof(int), typeof(GapPanel), new FrameworkPropertyMetadata(default(int), FrameworkPropertyMetadataOptions.AffectsRender, columnChanged)); 

     public static readonly DependencyProperty GapWidthProperty = 
      DependencyProperty.Register("GapWidth", typeof(double), typeof(GapPanel), new FrameworkPropertyMetadata(default(double), FrameworkPropertyMetadataOptions.AffectsRender)); 

     public static readonly RoutedEvent ColumnChangedEvent; 
     public static readonly RoutedEvent CloseGapEvent; 

     static GapPanel() { 
      ColumnChangedEvent = EventManager.RegisterRoutedEvent("ColumnChanged", RoutingStrategy.Bubble, typeof(RoutedEvent), typeof(GapPanel)); 
      CloseGapEvent = EventManager.RegisterRoutedEvent("CloseGap", RoutingStrategy.Bubble, typeof(RoutedEvent), typeof(GapPanel)); 
     } 

     public GapPanel() { 
      columns = new Dictionary<UIElement, int>(); 
      gapCoordinates = new Dictionary<int, double>(); 
      GapWidth = 0; 
      GapColumn = -1; 
     } 

     public int GapColumn { 
      get { return (int)GetValue(GapColumnProperty); } 
      set { SetValue(GapColumnProperty, value); } 
     } 

     public double GapWidth { 
      get { return (double)GetValue(GapWidthProperty); } 
      set { SetValue(GapWidthProperty, value); } 
     } 

     public double GapX { 
      get { 
       double value; 
       gapCoordinates.TryGetValue(GapColumn, out value); 
       return value; 
      } 
     } 

     public event PropertyChangedEventHandler PropertyChanged; 

     public event RoutedEventHandler ColumnChanged { 
      add { AddHandler(ColumnChangedEvent, value); } 
      remove { RemoveHandler(ColumnChangedEvent, value); } 
     } 

     public event RoutedEventHandler CloseGap { 
      add { AddHandler(CloseGapEvent, value); } 
      remove { RemoveHandler(CloseGapEvent, value); } 
     } 

     protected override Size ArrangeOverride(Size finalSize) { 
      Point location = new Point(); 
      double position = 0; 
      double columnWidth = 0; 
      int col = 0; 
      foreach (UIElement child in Children) { 
       columnWidth = Math.Max(columnWidth, child.DesiredSize.Width); 
       position += child.DesiredSize.Height; 
       if (position > finalSize.Height && columnWidth > 0) { 
        location.X += columnWidth; 
        if (col == GapColumn) { 
         location.X += GapWidth; 
        } 
        ++col; 
        columnWidth = 0; 
        position = child.DesiredSize.Height; 
        location.Y = 0; 
       } 
       columns[child] = col; 
       child.Arrange(new Rect(location, child.DesiredSize)); 

       location.Y = position; 
      } 

      return finalSize; 
     } 

     protected override Size MeasureOverride(Size availableSize) { 
      double width = 0, height = 0; 
      double position = 0; 
      double columnWidth = 0; 
      int col = 0; 
      foreach (UIElement child in Children) { 
       child.Measure(availableSize); 

       columnWidth = Math.Max(columnWidth, child.DesiredSize.Width); 
       position += child.DesiredSize.Height; 
       if (position > availableSize.Height && columnWidth > 0) { 
        width += columnWidth; 
        ++col; 
        columnWidth = child.DesiredSize.Width; 
        position = child.DesiredSize.Height; 
        height = Math.Max(height, child.DesiredSize.Height); 
       } 
       gapCoordinates[col] = width + columnWidth; 
      } 

      return new Size(width + GapWidth, height); 
     } 

     protected override void OnVisualChildrenChanged(DependencyObject visualAdded, DependencyObject visualRemoved) { 
      base.OnVisualChildrenChanged(visualAdded, visualRemoved); 
      UIElement element = visualAdded as UIElement; 
      if (element != null) { 
       element.PreviewMouseLeftButtonDown += expandAtVisual; 
      } 
      element = visualRemoved as UIElement; 
      if (element != null) { 
       element.PreviewMouseLeftButtonDown -= expandAtVisual; 
      } 
     } 

     private void expandAtVisual(object sender, MouseButtonEventArgs e) { 
      // find element column 
      int column = columns[(UIElement)sender]; 
      GapWidth = 0; 
      GapColumn = column; 
      if (opened == sender) { 
       RaiseEvent(new RoutedEventArgs(CloseGapEvent, this)); 
      } 
      opened = sender; 
     } 

     private void onPropertyChanged(string propertyName) { 
      PropertyChangedEventHandler handler = PropertyChanged; 
      if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); 
     } 

     private static void columnChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { 
      ((GapPanel)d).onPropertyChanged("GapX"); 
      ((GapPanel)d).RaiseEvent(new RoutedEventArgs(ColumnChangedEvent, d)); 
     } 
    } 
} 

Leave a comment nếu có bất cứ điều gì bạn cảm thấy tôi cần phải giải thích.

Ngoài ra, tôi không thể giúp quảng cáo cuốn sách "WPF4 Unleashed" của Adam Nathan. Nhiều nếu không phải tất cả mọi thứ tôi quản lý để làm ở trên được giải thích chi tiết trong cuốn sách này, vì vậy nó là một nguồn lực tuyệt vời cho bất cứ ai muốn tìm hiểu thêm về WPF.

+1

Có một số ý tưởng hay ở đây mà tôi có thể sử dụng. Tôi nghĩ rằng nó có thể được cải thiện bằng cách thực hiện một "ItemDetailTemplate'" thay vì cách DetailsPanel hiện đang được thực thi. DataContext có thể dễ dàng được thừa hưởng và nó sẽ cho phép XAML sạch hơn. Và đối với những gì nó có giá trị, tôi không thấy bất cứ điều gì sai với leaning nặng trên C# - nó làm cho XAML di động nhiều hơn nữa cuối cùng. – erodewald

+0

@Erode: Vâng, tôi đồng ý. Tôi cũng thấy khả năng thêm RoutedEvents cho 'OpeningGap',' OpenedGap' cũng như 'ClosingGap' và' ClosedGap', thay vì hai giá trị hiện tại. Ý tưởng về một ItemDetailTemplate thực sự tốt, điều đó có thể làm cho nó trở thành một thành phần "phù hợp" hơn, cũng như dọn dẹp trong XAML như bạn đã lưu ý. – Patrick

Các vấn đề liên quan