2012-07-19 3 views
1

타임 라인으로 약간의로드 블록을 쳤습니다. MVVM 기반 WPF 응용 프로그램에서 개발 중입니다.scrollviewer 캔버스에서 사용자가 클릭 한 컬렉션 결정

내 욕망은 일반적으로보기에 표시되는 것보다 많은 이벤트가 있기 때문에 사용자가보고 싶은 "빈"을 말할 수 있어야합니다. 이것은 근본적으로 코드 숨김으로 개발되어 사용자가 선택한 빈 위에 표시되는 작은 작은 스택 패널 일 것입니다. 자세한 내용은 아래를 참조하십시오. 그들은 뷰 모델에서 발생하는 I 이벤트를 기록하고

  • , 내가 이벤트로 참조합니다 :

    기본 배경이있다.

  • 시간 표시 막대에서보기에 50x50 캔버스 (이벤트 당 하나씩)로 표시 중입니다. 여기서 뉘앙스는 공간의 양이 매우 제한되어 있기 때문에 표시되는 실제 이벤트 수를 약간 오프셋 된 3 개의 스택으로 제한합니다 (표시된 카드 아래에있는 카드의 위쪽과 오른쪽에 서로 쌓인 카드를 상상해보십시오).)를 각각의 타임 블록에 대해 할당한다.

  • 각 시간마다 (30 초마다) 캔버스가 왼쪽으로 75 픽셀 스크롤되고 모든 그려진 요소가 물론 함께 움직입니다. 또한 이벤트에 대한 "휴지통"을 설정합니다. 본질적으로 0과 29.9 초 사이의 모든 것은 bin 0에 있고, 30 - 59.9는 bin 1입니다.

  • 바운드 이벤트를 표시하는 ItemsControl에 연결된 PreviewMouseLeftButtonDown 이벤트를 사용하고 있습니다.

현재 모든 기능이 작동합니다. 마우스 클릭을 수집 할 수 있으며 클릭 한 이벤트 그룹을 결정하기 위해 몇 가지 기본 수학을 사용하려고했습니다. 이것은 클릭 할 때 마우스의 X 위치를 기반으로하고 ScrollViewer 창의 모든 스크롤을 고려한 것입니다. 불행히도 나는 정확한 "bin"을 얻지 못했습니다. 내가 시도

다른 것들 :

  • 이가 소속 된 빈에 대한 정보를 포함하는 캔버스 요소에 태그에 추가합니다. 내가 얻은 코드의 ItemsSource에는 클릭 한 이벤트뿐만 아니라 모든 이벤트가 포함되어 있기 때문에 이는 작동하지 않습니다. 이것이 ItemsSource에 액세스하는 방법입니다.

    private void ItemsControl_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArds e) 
    { 
        var control = (ItemsControl)sender; 
        var isource = control.ItemsSource; 
        Debug.Assert(isource != null); 
    } 
    
  • 나는 ItemsControl에로 퍼팅하기 전에 StackPanel에의 내부를 둥지를 시도했습니다. 이것은 중첩 목록이있을 때 효과적 이었지만 목록 목록을 얻지 못하면 무너졌습니다. 이 시점에서 실행 가능한 옵션이 될지 확실하지 않습니다.

나는 (그것을 참조 할 수 있습니다 사람들을 위해) 이것을 가지고 XAML은 다음과 같습니다 :이 그리는 데 사용되는 DataTemplate을 주택으로 관심의

주요 ItemsControl에 마지막 하나입니다 ScrollViewer에서 캔버스의 이벤트. 나머지 두 개는 타임 라인의 맨 아래에있는 타임 스탬프 용입니다.

<UserControl 
    x:Class="Removed.Views.TransitionTimeline" 
    x:ClassModifier="internal" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    mc:Ignorable="d" 
    d:DesignHeight="300" d:DesignWidth="300"> 
    <UserControl.Resources> 
    <Style x:Key="ISTCanvasStyle" TargetType="Canvas"> 
     <Setter Property="Background" Value="Transparent" /> 
    </Style> 

    <Style x:Key="ISTBorderStyle" TargetType="Border"> 
     <Setter Property="BorderThickness" Value="3" /> 
     <Setter Property="BorderBrush" Value="{Binding ColorBrush}" /> 
     <Setter Property="CornerRadius" Value="8" /> 
     <Setter Property="HorizontalAlignment" Value="Center" /> 
     <Setter Property="VerticalAlignment" Value="Center" /> 
     <Setter Property="Background" Value="#FF555555" /> 
     <Setter Property="Height" Value="50" /> 
     <Setter Property="Width" Value="50" /> 
    </Style> 

    <Style x:Key="ISTTextBlockStyle" TargetType="TextBlock"> 
     <Setter Property="Text" Value="{Binding ShortName}" /> 
     <Setter Property="HorizontalAlignment" Value="Center" /> 
     <Setter Property="VerticalAlignment" Value="Center" /> 
     <Setter Property="FontWeight" Value="Bold" /> 
     <Setter Property="FontSize" Value="40" /> 
     <Setter Property="Foreground" Value="White" /> 
     <Setter Property="TextAlignment" Value="Center" /> 
    </Style> 

    <Style x:Key="EventCountTextStyle" TargetType="TextBlock"> 
     <Setter Property="Text" Value="{Binding ExtraEvents}" /> 
     <Setter Property="Canvas.Top" Value="-15" /> 
     <Setter Property="Canvas.Left" Value="-25" /> 
     <Setter Property="FontWeight" Value="Bold" /> 
     <Setter Property="FontSize" Value="13" /> 
     <Setter Property="Foreground" Value="{Binding EventTextColorBrush}" /> 
     <Setter Property="TextAlignment" Value="Center" /> 
    </Style> 

    <DataTemplate x:Key="IndividualStateTransitions"> 
     <Canvas Margin="{Binding Margin}" Style="{ StaticResource ISTCanvasStyle}" > 
     <Border Canvas.Left="-12.5" Style="{ StaticResource ISTBorderStyle}" > 
      <TextBlock Style="{StaticResource ISTTextBlockStyle}" /> 
     </Border> 
     <TextBlock Style="{StaticResource EventCountTextStyle}" /> 
     </Canvas> 
    </DataTemplate> 

    <DataTemplate x:Key="IST"> 
     <ItemsControl 
      ItemsSource="{Binding}" 
      ItemTemplate="{StaticResource IndividualStateTransitions}" 
      PreviewMouseLeftButtonDown="ItemsControl_PreviewMouseLeftButtonDown" 
      Width="75"> 
     <ItemsControl.ItemsPanel> 
      <ItemsPanelTemplate> 
      <Canvas /> 
      </ItemsPanelTemplate> 
     </ItemsControl.ItemsPanel> 
     <ItemsControl.ItemContainerStyle> 
      <Style TargetType="ContentPresenter"> 
      <Setter Property="Canvas.ZIndex" Value="{Binding ZIndex}" /> 
      </Style> 
     </ItemsControl.ItemContainerStyle> 
     </ItemsControl> 
    </DataTemplate> 

    <DataTemplate x:Key="BottomTimeBar"> 
     <Canvas> 
     <Line X1="{Binding DashX}" X2="{Binding DashX}" Y1="100" Y2="0" Stroke="#FF646464" StrokeThickness="1" StrokeDashArray="5" StrokeDashCap="Round" /> 
     <TextBlock Canvas.ZIndex="-999" Width="50" TextAlignment="Center" Text="{Binding TimerText}" Canvas.Left="{Binding BlockLeft}" 
         Canvas.Top="85" Foreground="White" Background="#FF444444" FontSize="13" /> 
     </Canvas> 
    </DataTemplate> 

    </UserControl.Resources> 
    <Grid Name="TimelineGrid" Height="192"> 
    <Grid.RowDefinitions> 
     <RowDefinition Height="92" /> 
     <RowDefinition Height="100" /> 
    </Grid.RowDefinitions> 

    <Canvas Grid.Row="0" Width="1920" Height="100"> 
     <ScrollViewer    
      Width="1920" 
      Height="100" 
      Name="_timelineScrollViewer2" 
      CanContentScroll="True" 
      Background="Transparent" 
      HorizontalScrollBarVisibility="Hidden" 
      VerticalScrollBarVisibility="Hidden"> 
     <Canvas Width="9999" Name="_timelineCanvas2"> 
     </Canvas> 
     </ScrollViewer> 
    </Canvas> 

    <Canvas Grid.Row="1" Name="MainCanvas" Width="1920" Height="100" > 
     <Line X1="0" X2="1920" Y1="0" Y2="0" Stroke="#FFD0D0D0" StrokeThickness="3"> 
     <Line.Effect> 
      <DropShadowEffect BlurRadius="3" ShadowDepth="3" /> 
     </Line.Effect> 
     </Line> 
     <Line X1="0" X2="1920" Y1="55" Y2="55" Stroke="#FFD0D0D0" StrokeThickness="3"> 
     <Line.Effect> 
      <DropShadowEffect BlurRadius="3" ShadowDepth="3" /> 
     </Line.Effect> 
     </Line> 
     <ScrollViewer    
      Width="1920" 
      Height="100" 
      Name="_timelineScrollViewer" 
      CanContentScroll="True" 
      Background="Transparent" 
      HorizontalScrollBarVisibility="Hidden" 
      VerticalScrollBarVisibility="Hidden" 
      PreviewMouseLeftButtonDown="TimelineScrollViewerLeftMouseDown" 
      PreviewMouseLeftButtonUp="LeftMouseUp" 
      PreviewMouseMove="TimelineScrollViewerMouseMove" 
      PreviewMouseWheel="TimelineScrollViewerPreviewMouseWheel" 
      ScrollChanged="OnTimelineScrollChanged" ClipToBounds="False"> 
     <Canvas Width="9999" Name="_timelineCanvas"> 
      <Line Canvas.ZIndex="-1000" Name="CurrentTimeLine" X1="1280" X2="1280" Y1="0" Y2="100" Stroke="#FFD0D0D0" StrokeThickness="3"> 
      <Line.Effect> 
       <DropShadowEffect BlurRadius="3" ShadowDepth="3" /> 
      </Line.Effect> 
      </Line> 
      <ItemsControl ItemsSource="{Binding BottomTimeBarData}" ItemTemplate="{StaticResource BottomTimeBar}" Canvas.Left="{Binding LeftScroll}"> 
      <ItemsControl.ItemsPanel> 
       <ItemsPanelTemplate> 
       <Canvas /> 
       </ItemsPanelTemplate> 
      </ItemsControl.ItemsPanel> 
      </ItemsControl> 
      <ItemsControl ItemsSource="{Binding BottomTimeBarDataPast}" ItemTemplate="{StaticResource BottomTimeBar}" Canvas.Left="{Binding LeftScroll}"> 
      <ItemsControl.ItemsPanel> 
       <ItemsPanelTemplate> 
       <Canvas /> 
       </ItemsPanelTemplate> 
      </ItemsControl.ItemsPanel> 
      </ItemsControl> 

      <ItemsControl ItemsSource="{Binding DisplayObject}" ItemTemplate="{StaticResource IndividualStateTransitions}" Canvas.Left="{Binding LeftScroll}" Canvas.Top="15" Margin="0.0, 25.5" 
         PreviewMouseLeftButtonDown="ItemsControl_PreviewMouseLeftButtonDown" > 
      <ItemsControl.ItemsPanel> 
       <ItemsPanelTemplate> 
       <StackPanel /> 
       </ItemsPanelTemplate> 
      </ItemsControl.ItemsPanel> 
      <ItemsControl.ItemContainerStyle> 
       <Style TargetType="ContentPresenter"> 
       <Setter Property="Canvas.ZIndex" Value="{Binding ZIndex}" /> 
       </Style> 
      </ItemsControl.ItemContainerStyle> 
      </ItemsControl> 
     </Canvas> 
     </ScrollViewer> 
    </Canvas> 
    </Grid> 
</UserControl> 

질문 사항이 있으면 알려주십시오. 무슨 일이 일어나는지 분명히 밝히는 것이 행복 할 것 같습니다.궁극적으로 내가 찾고있는 것은 사용자가보고 싶은 "bin"을 결정하는 방법입니다.

업데이트 1 : 그려진 개체에 대한 추가 정보.

내 자신의 내부 클래스를 정의 했으므로 ObservableCollection의 데이터 유형으로 사용할 수 있습니다.이 데이터는이 경우에 바인딩됩니다.

internal class DisplayObjects : INotifyPropertyChanged 
{ 
    private int _elementbin; 
    public int ElementBin 
    { 
     get { return _elementbin; } 
     set 
     { 
      _elementbin = value; 

      if (PropertyChanged != null) 
       PropertyChanged(this, new PropertyChangedEventArgs("ElementBin")); 
     } 
    } 

    private string _shortName; 
    public string ShortName 
    { 
     get { return _shortName; } 
     set 
     { 
      _shortName = value; 

      if (PropertyChanged != null) 
       PropertyChanged(this, new PropertyChangedEventArgs("ShortName")); 
     } 
    } 

    private string _margin; 
    public string Margin 
    { 
     get { return _margin; } 
     set 
     { 
      _margin = value; 

      if (PropertyChanged != null) 
       PropertyChanged(this, new PropertyChangedEventArgs("Margin")); 
     } 
    } 

    private string _extraevents; 
    public string ExtraEvents 
    { 
     get { return _extraevents; } 
     set 
     { 
      _extraevents = value; 

      if (PropertyChanged != null) 
       PropertyChanged(this, new PropertyChangedEventArgs("ExtraEvents")); 
     } 
    } 

    public Color EventTextColor { get; set; } 

    public SolidColorBrush EventTextColorBrush 
    { 
     get 
     { 
      return new SolidColorBrush(EventTextColor); 
     } 
    } 

    private int _zindex; 
    public int ZIndex 
    { 
     get { return _zindex; } 
     set 
     { 
      _zindex = value; 

      if (PropertyChanged != null) 
       PropertyChanged(this, new PropertyChangedEventArgs("ZIndex")); 
     } 
    } 

    public Color Color { get; set; } 

    public SolidColorBrush ColorBrush 
    { 
     get { return new SolidColorBrush(Color); } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 
} 

이벤트 수집기에 가입되어 이벤트를 전송할 때이를 잡을 수 있습니다. 내 OnEventReceived 메서드가 트리거됩니다. 이 방법에 대해 알아야 할 것은 이벤트가 수신 한 이벤트에서 정보를 가져 와서 이벤트가 발생한 시간을 기준으로 어떤 bin으로 분류해야하는지 결정하는 것입니다. 이 내 DrawObject 메서드에 대한 호출을 트리거합니다.

이것을 시도하고 싶다면 stvm을 하드 코딩 된 것으로 바꿀 수 있습니다. 내가 실제 데이터를 제공 할 수는 없습니다. stvm.Color는 이벤트 유형을 나타내는 색상입니다. stvm.ShortName은 하나의 문자입니다. _bin은 각 bin에서 발생한 총 이벤트 수를 추적하는 List<Int>입니다. position은 속한 빈의 숫자 이벤트입니다. 첫 번째 이벤트가 1 일 경우 첫 번째 이벤트입니다. 10 번째 이벤트이면 10이됩니다.

FindLastVisualChild 메서드는 주어진 DisplayObject에 대한 세 번째 DisplayObject 위치의 인덱스를 반환하기위한 것입니다. 큰 상자. 이를 통해 "+ X more"라는 태그를 업데이트 할 수 있습니다. 스택의 이벤트.

private void DrawObject(EventViewModel stvm, int position, int bin) 
{ 
    var margin = ""; 
    var zindex = 0; 
    var left = bin * 75.0; 
    var textColor = Colors.Transparent; 
    var extraEvents = "+ "; 
    switch (position) 
    { 
     case 1: 
      left += 12.5; 
      margin = left + ", -5"; 
      zindex = 3; 
      DisplayObject.Add(new DisplayObjects 
      { 
       Color = stvm.Color, 
       ShortName = stvm.ShortName, 
       Margin = margin, 
       ZIndex = zindex, 
       EventTextColor = textColor, 
       ExtraEvents = extraEvents, 
       ElementBin = bin 
      }); 
      break; 
     case 2: 
      left += 22.5; 
      margin = left + ", -15"; 
      zindex = 2; 
      DisplayObject.Add(new DisplayObjects 
      { 
       Color = stvm.Color, 
       ShortName = stvm.ShortName, 
       Margin = margin, 
       ZIndex = zindex, 
       EventTextColor = textColor, 
       ExtraEvents = extraEvents, 
       ElementBin = bin 
      }); 
      break; 
     case 3: 
      left += 32.5; 
      margin = left + ", -25"; 
      zindex = 1; 
      DisplayObject.Add(new DisplayObjects 
      { 
       Color = stvm.Color, 
       ShortName = stvm.ShortName, 
       Margin = margin, 
       ZIndex = zindex, 
       EventTextColor = textColor, 
       ExtraEvents = extraEvents, 
       ElementBin = bin 
      }); 
      break; 
     default: 
      //left += 32.5; 
      //margin = left + ", -25"; 
      //DisplayObject.Add(new DisplayObjects { Color = stvm.Color, ShortName = stvm.ShortName, Margin = margin, ZIndex = zindex, EventTextColor = textColor, ExtraEvents = extraEvents }); 
      extraEvents += (_bins[bin] - 3) + " more."; 
      var test = FindLastVisualChild(bin); 
      DisplayObject[test].EventTextColor = Colors.White; 
      DisplayObject[FindLastVisualChild(bin)].ExtraEvents = extraEvents; 
      break; 
    } 
} 

private int FindLastVisualChild(int bin) 
{ 
    var sum = 0; 
    for (var idx = 0; idx <= bin; idx++) 
     if (_bins[idx] <= 3) 
      sum += _bins[idx]; 
     else 
      sum += 3; 
    return (sum - 1); 
} 
+1

왜 'ItemsControl' 대신'ItemsControl'의 개별 항목에 클릭 이벤트를 추가하지 않으시겠습니까? – Rachel

+0

나는 그것을 지금 시도했다. 실제로 사용자가 클릭 한 캔버스를 가져 와서 해당 캔버스의 하위 항목에 액세스 할 수 있습니다. 그러나 내가 실제로 캔버스에 배치 한 태그를 실제로 얻을 수 있는지는 확실하지 않습니다. 이것은 실제로 내가 속한 bin을 식별 할 수있는 지점까지 나를 데려다주지는 않습니다. –

답변

0

David와 Rachel에게 큰 감사를드립니다. 그들의 의견은 내가 결국 일하고있는 대답으로 나를 이끌었다.

이 다음에 와서 읽고 읽는 사람을위한 참고서입니다. 여기 내가 한 일이있다.

IndividualStateTransistions에 대한 데이터 템플릿에서 Canvas에 Tag = "{Binding ElementBin}"으로 추가했습니다. 그런 다음 해당 요소가 이벤트를 빈으로 필터링하는 코드에 속한 bin 번호를 추가했습니다.

레이첼의 제안에 따라 마우스 클릭 이벤트를이 캔버스로 옮겼습니다. 코드에서

나는 다윗이 얻을 제안 있었는지 적응 뒤에 다음 OnMouseClickEvent 방법

을 ...

var control = (Canvas)sender; 
var item = control.DataContext as DisplayObjects; 
var itembin = item.ElementBin; 

이 나에게 이벤트의 해당 그룹이 속하는 날의 다음 단계로 계속 할 수 있습니다, 빈을 제공합니다.

다시 한 번 감사드립니다.

1

e.OriginalSource을 사용해 보셨습니까?

내가 분명히 프로젝트를 재현 할 수 있지만, 지금까지 내가 추측 할 수, 당신이 사용하여 클릭 한 캔버스 잡아 얻을 수 있어야합니다 :

var canvas = e.OriginalSource as Canvas 

을 한 다음 얻을 수 있어야합니다 해당 항목을 쉽게 canvas의 DataContext로 이해할 수 있습니다.

var item = canvas.DataContext as MyItemViewModel; 

그러나 제가 작성한 것처럼 이것은 어림짐작입니다. 앱에서 더 명확하게 볼 수있는 더 많은 정보 (예 : 컬렉션에 항목을 추가하는 코드)를 게시해야합니다.

+0

몇 가지 추가 정보가 있습니다. 그게 도움이되는지 알려주세요. 그동안 나는 여기서 한 말로 내가 할 수있는 것을 보게 될 것입니다. –

관련 문제