Browse Source

Debugger tooltips - added DebuggerTooltipControl.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@4589 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Martin Koníček 17 years ago
parent
commit
6a27467bda
  1. 11
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/TreeModel/TreeNode.cs
  2. 12
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/GridVisualizer/GridVisualizerWindow.xaml.cs
  3. 54
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/GridVisualizer/LazyListView.cs
  4. 31
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/GridVisualizer/ValueProviders/VirtualizingIEnumerable.cs
  5. 10
      src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj
  6. 176
      src/Main/Base/Project/Src/Services/Debugger/DebuggerTooltipControl.xaml
  7. 103
      src/Main/Base/Project/Src/Services/Debugger/DebuggerTooltipControl.xaml.cs
  8. 29
      src/Main/Base/Project/Src/Services/Debugger/ITooltip.cs
  9. 25
      src/Main/Base/Project/Src/Services/Debugger/ITreeNode.cs
  10. 120
      src/Main/Base/Project/Src/Services/Debugger/LazyItemsControl.cs
  11. 58
      src/Main/Base/Project/Src/Services/Debugger/VirtualizingIEnumerable.cs
  12. 67
      src/Main/Base/Project/Src/Util/ScrollUtils.cs

11
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/TreeModel/TreeNode.cs

@ -7,6 +7,7 @@ @@ -7,6 +7,7 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using ICSharpCode.SharpDevelop.Debugging;
namespace Debugger.AddIn.TreeModel
{
@ -14,7 +15,7 @@ namespace Debugger.AddIn.TreeModel @@ -14,7 +15,7 @@ namespace Debugger.AddIn.TreeModel
/// A node in the variable tree.
/// The node is imutable.
/// </summary>
public class TreeNode: IComparable<TreeNode>
public class TreeNode: IComparable<TreeNode>, ITreeNode
{
Image image = null;
string name = string.Empty;
@ -32,7 +33,8 @@ namespace Debugger.AddIn.TreeModel @@ -32,7 +33,8 @@ namespace Debugger.AddIn.TreeModel
set { name = value; }
}
public virtual string Text {
public virtual string Text
{
get { return text; }
protected set { text = value; }
}
@ -47,9 +49,12 @@ namespace Debugger.AddIn.TreeModel @@ -47,9 +49,12 @@ namespace Debugger.AddIn.TreeModel
protected set { childNodes = value; }
}
IEnumerable<ITreeNode> ITreeNode.ChildNodes {
get { return this.childNodes; }
}
public TreeNode()
{
}
public TreeNode(Image image, string name, string text, string type, IEnumerable<TreeNode> childNodes)

12
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/GridVisualizer/GridVisualizerWindow.xaml.cs

@ -35,6 +35,10 @@ namespace Debugger.AddIn.Visualizers.GridVisualizer @@ -35,6 +35,10 @@ namespace Debugger.AddIn.Visualizers.GridVisualizer
public GridVisualizerWindow()
{
InitializeComponent();
this.debuggerService = DebuggerService.CurrentDebugger as WindowsDebugger;
if (debuggerService == null)
throw new ApplicationException("Only windows debugger is currently supported");
}
private void btnInspect_Click(object sender, RoutedEventArgs e)
@ -45,10 +49,6 @@ namespace Debugger.AddIn.Visualizers.GridVisualizer @@ -45,10 +49,6 @@ namespace Debugger.AddIn.Visualizers.GridVisualizer
if (listViewScroller != null)
listViewScroller.ScrollToVerticalOffset(0);
this.debuggerService = DebuggerService.CurrentDebugger as WindowsDebugger;
if (debuggerService == null)
throw new ApplicationException("Only windows debugger is currently supported");
Value val = null;
try
{
@ -77,9 +77,9 @@ namespace Debugger.AddIn.Visualizers.GridVisualizer @@ -77,9 +77,9 @@ namespace Debugger.AddIn.Visualizers.GridVisualizer
DebugType iEnumerableType, itemType;
if (val.Type.ResolveIEnumerableImplementation(out iEnumerableType, out itemType))
{
var lazyListViewWrapper = new LazyItemsControl<ObjectValue>(this.listView);
var lazyListViewWrapper = new LazyItemsControl<ObjectValue>(this.listView, 24);
var enumerableValuesProvider = new EnumerableValuesProvider(val.ExpressionTree, iEnumerableType, itemType);
lazyListViewWrapper.ItemsSource = enumerableValuesProvider.ItemsSource;
lazyListViewWrapper.ItemsSource = new VirtualizingIEnumerable<ObjectValue>(enumerableValuesProvider.ItemsSource);
gridValuesProvider = enumerableValuesProvider;
}
else

54
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/GridVisualizer/LazyListView.cs

@ -10,58 +10,4 @@ using System.Windows.Controls; @@ -10,58 +10,4 @@ using System.Windows.Controls;
namespace Debugger.AddIn.Visualizers.GridVisualizer
{
/// <summary>
/// ListView that takes VirtualizingIEnumerable as source,
/// and requests additional items from the source as needed when scrolling.
/// </summary>
public class LazyItemsControl<T>
{
private ItemsControl itemsControl;
public LazyItemsControl(ItemsControl wrappedItemsControl)
{
if (wrappedItemsControl == null)
throw new ArgumentNullException("wrappedListView");
this.itemsControl = wrappedItemsControl;
this.itemsControl.AddHandler(ScrollViewer.ScrollChangedEvent, new ScrollChangedEventHandler(handleListViewScroll));
}
/// <summary> The collection that underlying ItemsControl sees. </summary>
private VirtualizingIEnumerable<T> itemsSourceVirtualized;
private IEnumerable<T> itemsSource;
/// <summary>
/// IEnumerable providing all the items. LazyItemsControl pulls next items from this source when scrolled to bottom.
/// </summary>
public IEnumerable<T> ItemsSource
{
get
{
return itemsSource;
}
set
{
this.itemsSource = value;
// virtualize IEnumerable and use it as ItemsControl source
// -> ItemsControl sees only a few items, more are added when scrolled to bottom
this.itemsSourceVirtualized = new VirtualizingIEnumerable<T>(value);
this.itemsSourceVirtualized.AddNextItems(25);
this.itemsControl.ItemsSource = this.itemsSourceVirtualized;
}
}
private void handleListViewScroll(object sender, ScrollChangedEventArgs e)
{
if (e.VerticalChange > 0)
{
// scrolled to bottom
if (e.VerticalOffset == this.itemsSourceVirtualized.Count - e.ViewportHeight)
{
this.itemsSourceVirtualized.AddNextItems(1);
}
}
}
}
}

31
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/GridVisualizer/ValueProviders/VirtualizingIEnumerable.cs

@ -10,34 +10,5 @@ using System.Collections.ObjectModel; @@ -10,34 +10,5 @@ using System.Collections.ObjectModel;
namespace Debugger.AddIn.Visualizers.GridVisualizer
{
/// <summary>
/// A wrapper around IEnumerable&lt;T&gt; with RequestNextItems method for pulling additional items
/// from the IEnumerable&lt;T&gt; when needed.
/// Can be used as source for <see cref="LazyListView" />.
/// (Used to wrap EnumerableValuesProvider.ItemsSource)
/// </summary>
public class VirtualizingIEnumerable<T> : ObservableCollection<T>
{
private IEnumerator<T> originalSourceEnumerator;
public VirtualizingIEnumerable(IEnumerable<T> originalSource)
{
if (originalSource == null)
throw new ArgumentNullException("originalSource");
this.originalSourceEnumerator = originalSource.GetEnumerator();
}
/// <summary>
/// Requests next <paramref name="count"/> items from underlying IEnumerable source and adds them to the collection.
/// </summary>
public void AddNextItems(int count)
{
for (int i = 0; i < count; i++)
{
if (!originalSourceEnumerator.MoveNext()) break;
this.Add(originalSourceEnumerator.Current);
}
}
}
}

10
src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj

@ -215,6 +215,14 @@ @@ -215,6 +215,14 @@
<Compile Include="Src\Project\Solution\ProjectTypeGuids.cs" />
<Compile Include="Src\Services\Debugger\BreakpointBookmark.cs" />
<Compile Include="Src\Services\Debugger\BreakpointBookmarkEventArgs.cs" />
<Compile Include="Src\Services\Debugger\DebuggerTooltipControl.xaml.cs">
<DependentUpon>DebuggerTooltipControl.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="Src\Services\Debugger\ITooltip.cs" />
<Compile Include="Src\Services\Debugger\ITreeNode.cs" />
<Compile Include="Src\Services\Debugger\LazyItemsControl.cs" />
<Compile Include="Src\Services\Debugger\VirtualizingIEnumerable.cs" />
<Compile Include="Src\Services\DisplayBinding\ExternalProcessDisplayBinding.cs" />
<Compile Include="Src\Services\DisplayBinding\ISecondaryDisplayBinding.cs" />
<Compile Include="Src\Services\DisplayBinding\ShellExecuteDisplayBinding.cs" />
@ -772,6 +780,7 @@ @@ -772,6 +780,7 @@
<Compile Include="Src\Project\CompilableProject.cs" />
<Compile Include="Src\Project\MSBuildInternals.cs" />
<Compile Include="Src\Util\Pair.cs" />
<Compile Include="Src\Util\ScrollUtils.cs" />
<Compile Include="Src\Util\SDWindowsFormsHost.cs" />
<Compile Include="Src\Util\Set.cs" />
<Compile Include="Src\Util\ReadOnlyCollectionWrapper.cs" />
@ -866,6 +875,7 @@ @@ -866,6 +875,7 @@
<Page Include="Src\Gui\Dialogs\TabbedOptionsDialog.xaml" />
<Page Include="Src\Gui\Dialogs\TreeViewOptionsDialog.xaml" />
<Page Include="Src\Gui\Workbench\WpfWorkbench.xaml" />
<Page Include="Src\Services\Debugger\DebuggerTooltipControl.xaml" />
<Page Include="Src\TextEditor\Gui\Dialogs\GotoDialog.xaml" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />

176
src/Main/Base/Project/Src/Services/Debugger/DebuggerTooltipControl.xaml

@ -0,0 +1,176 @@ @@ -0,0 +1,176 @@
<UserControl x:Class="ICSharpCode.SharpDevelop.Debugging.DebuggerTooltipControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<UserControl.Resources>
<!-- TODO move styles to ResourceDictionary -->
<Style x:Key="ExpandCollapseToggleStyle"
TargetType="{x:Type ToggleButton}">
<Setter Property="Focusable"
Value="False"/>
<Setter Property="Width"
Value="19"/>
<Setter Property="Height"
Value="13"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border Width="19"
Height="13"
Background="Transparent">
<Border Width="9"
Height="9"
BorderThickness="1"
BorderBrush="#FF7898B5"
CornerRadius="1"
SnapsToDevicePixels="true">
<Border.Background>
<LinearGradientBrush StartPoint="0,0"
EndPoint="1,1">
<LinearGradientBrush.GradientStops>
<GradientStop Color="White"
Offset=".2"/>
<GradientStop Color="#FFC0B7A6"
Offset="1"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Border.Background>
<Path x:Name="ExpandPath"
Margin="1,1,1,1"
Fill="Black"
Data="M 0 2 L 0 3 L 2 3 L 2 5 L 3 5 L 3 3 L 5 3 L 5 2 L 3 2 L 3 0 L 2 0 L 2 2 Z"/>
</Border>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked"
Value="True">
<Setter Property="Data"
TargetName="ExpandPath"
Value="M 0 2 L 0 3 L 5 3 L 5 2 Z"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="upDownBorderStyle" TargetType="{x:Type Border}">
<Setter Property="BorderBrush" Value="Gray" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="Margin" Value="0" />
<Setter Property="Background" Value="#FFECF7FC" />
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsEnabled}" Value="False">
<Setter Property="Background" Value="#FFE0E0E0"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
<Style x:Key="upButtonStyle" TargetType="{x:Type RepeatButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type RepeatButton}">
<Border Style="{StaticResource upDownBorderStyle}" BorderThickness="1 1 1 0">
<ContentPresenter HorizontalAlignment="Center"></ContentPresenter>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="downButtonStyle" TargetType="{x:Type RepeatButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type RepeatButton}">
<Border Style="{StaticResource upDownBorderStyle}" BorderThickness="1 0 1 1">
<ContentPresenter HorizontalAlignment="Center"></ContentPresenter>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<StackPanel Orientation="Vertical">
<RepeatButton Name="btnUp" Style="{StaticResource upButtonStyle}" Content="^" Click="BtnUp_Click"></RepeatButton>
<DataGrid VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Disabled"
GridLinesVisibility="None"
RowHeight="20" MaxHeight="202"
SelectionMode="Single"
SelectionUnit="FullRow"
ItemsSource="{Binding}"
Name="dataGrid"
AutoGenerateColumns="False"
CanUserAddRows="False" HeadersVisibility="None"
BorderBrush="Gray"
BorderThickness="1">
<DataGrid.Background>
<LinearGradientBrush StartPoint="0,-0.03" EndPoint="0,1">
<GradientStop Color="White"/>
<GradientStop Color="#FFFAFCFE" Offset="0.983"/>
<GradientStop Color="#FFECF7FC" Offset="0.07"/>
<GradientStop Color="#FFEEF7FA" Offset="0.436"/>
</LinearGradientBrush>
</DataGrid.Background>
<DataGrid.RowStyle>
<Style TargetType="{x:Type DataGridRow}">
<Setter Property="Background" Value="Transparent"></Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#FFE2F6FE" />
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
<DataGrid.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="Focusable" Value="false" />
<Setter Property="BorderThickness" Value="0" />
</Style>
</DataGrid.CellStyle>
<DataGrid.Columns>
<DataGridTemplateColumn> <!-- "Plus" expander -->
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid Background="White">
<StackPanel VerticalAlignment="Center">
<ToggleButton x:Name="PropertyExpander" Style="{StaticResource ExpandCollapseToggleStyle}" Click="Expander_Click" Padding="0" Margin="0 0 0 0" />
</StackPanel>
</Grid>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=ShowPropertyButton}" Value="False">
<Setter TargetName="PropertyExpander"
Property="Visibility" Value="Hidden"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<!-- Icon
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn> -->
<DataGridTemplateColumn MinWidth="20" Header="Name"> <!-- Name -->
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Border BorderBrush="#FFDDDDDD" BorderThickness="0 0 1 0">
<TextBlock Margin="0 0 6 0" Text="{Binding Path=Name, Mode=OneWay}"></TextBlock>
</Border>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<!-- Visualizer picker
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn> -->
<!-- Value -->
<DataGridTextColumn MinWidth="20"
Header="Value" Width="Auto"
Binding="{Binding Path=Value, Mode=OneWay}"/>
</DataGrid.Columns>
</DataGrid>
<RepeatButton Name="btnDown" Style="{StaticResource downButtonStyle}" Content="v" Click="BtnDown_Click"></RepeatButton>
</StackPanel>
</UserControl>

103
src/Main/Base/Project/Src/Services/Debugger/DebuggerTooltipControl.xaml.cs

@ -0,0 +1,103 @@ @@ -0,0 +1,103 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Martin Koníček" email="martin.konicek@gmail.com"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
namespace ICSharpCode.SharpDevelop.Debugging
{
/// <summary>
/// Default Control used as content of SharpDevelop debugger tooltips.
/// </summary>
public partial class DebuggerTooltipControl : UserControl, ITooltip
{
public DebuggerTooltipControl()
{
InitializeComponent();
}
private LazyItemsControl<ITreeNode> lazyGrid;
private IEnumerable<ITreeNode> itemsSource;
public IEnumerable<ITreeNode> ItemsSource
{
set
{
this.itemsSource = value;
this.lazyGrid = new LazyItemsControl<ITreeNode>(this.dataGrid, 12);
lazyGrid.ItemsSource = new VirtualizingIEnumerable<ITreeNode>(value);
this.dataGrid.AddHandler(ScrollViewer.ScrollChangedEvent, new ScrollChangedEventHandler(handleScroll));
if (this.lazyGrid.ItemsSourceTotalCount != null)
{
btnUp.Visibility = btnDown.Visibility =
this.lazyGrid.ItemsSourceTotalCount.Value <= 10 ? Visibility.Collapsed : Visibility.Visible;
}
}
get
{
return this.itemsSource;
}
}
/// <summary>
/// Determines whether DebuggerTooltipControl should be displayed in WPF Popup.
/// </summary>
public bool ShowAsPopup {
get {
return true;
}
}
/// <summary>
/// Closes the debugger Popup containing this control. Also closes all child Popups.
/// </summary>
/// <returns></returns>
public bool Close()
{
throw new NotImplementedException();
}
private void Expander_Click(object sender, RoutedEventArgs e)
{
var clickedButton = (ToggleButton)e.OriginalSource;
Point buttonPos = clickedButton.PointToScreen(new Point(0, 0));
if (clickedButton.IsChecked.GetValueOrDefault(false))
{
// open child Popup
}
else
{
// close child Popups
}
}
private void handleScroll(object sender, ScrollChangedEventArgs e)
{
btnUp.IsEnabled = !this.lazyGrid.IsScrolledToStart;
btnDown.IsEnabled = !this.lazyGrid.IsScrolledToEnd;
}
void BtnUp_Click(object sender, RoutedEventArgs e)
{
this.lazyGrid.ScrollViewer.ScrollUp(1);
}
void BtnDown_Click(object sender, RoutedEventArgs e)
{
this.lazyGrid.ScrollViewer.ScrollDown(1);
}
}
}

29
src/Main/Base/Project/Src/Services/Debugger/ITooltip.cs

@ -0,0 +1,29 @@ @@ -0,0 +1,29 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Martin Koníček" email="martin.konicek@gmail.com"/>
// <version>$Revision$</version>
// </file>
using System;
namespace ICSharpCode.SharpDevelop.Debugging
{
/// <summary>
/// Content of debugger tooltip, specifying whether it should be displayed in a WPF Popup.
/// </summary>
public interface ITooltip
{
/// <summary>
/// If true, this ITooltip will be displayed in a WPF Popup.
/// Otherwise this will be displayed in a WPF Tooltip.
/// WPF Popups are (unlike WPF Tooltips) focusable.
/// </summary>
bool ShowAsPopup { get; }
/// <summary>
/// Closes this debugger tooltip.
/// </summary>
/// <returns>True if Close succeeded, false otherwise.</returns>
bool Close();
}
}

25
src/Main/Base/Project/Src/Services/Debugger/ITreeNode.cs

@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Martin Koníček" email="martin.konicek@gmail.com"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
namespace ICSharpCode.SharpDevelop.Debugging
{
/// <summary>
/// Node that can be bound to DebuggerTooltipControl.
/// </summary>
public interface ITreeNode
{
string Name { get; }
string Text { get; }
string Type { get; }
IEnumerable<ITreeNode> ChildNodes { get; }
}
}

120
src/Main/Base/Project/Src/Services/Debugger/LazyItemsControl.cs

@ -0,0 +1,120 @@ @@ -0,0 +1,120 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Martin Koníček" email="martin.konicek@gmail.com"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
using System.Windows.Controls;
namespace ICSharpCode.SharpDevelop.Debugging
{
/// <summary>
/// ItemsControl wrapper that takes VirtualizingIEnumerable as source,
/// and adds additional items from the source to underlying ItemsControl when scrolled to bottom.
/// </summary>
public class LazyItemsControl<T>
{
private ItemsControl itemsControl;
private int initialItemsCount;
/// <summary>
/// Creates new instance of LazyItemsControl.
/// </summary>
/// <param name="wrappedItemsControl">ItemsControl to wrap and add items to it when scrolled to bottom.</param>
/// <param name="initialItemsCount">Number of items to be initially displayed in wrapped ItemsControl.</param>
public LazyItemsControl(ItemsControl wrappedItemsControl, int initialItemsCount)
{
if (wrappedItemsControl == null)
throw new ArgumentNullException("wrappedItemsControl");
this.initialItemsCount = initialItemsCount;
this.itemsControl = wrappedItemsControl;
this.itemsControl.AddHandler(ScrollViewer.ScrollChangedEvent, new ScrollChangedEventHandler(handleScroll));
}
private ScrollViewer scrollViewerCached;
public ScrollViewer ScrollViewer
{
get
{
if (this.scrollViewerCached == null)
this.scrollViewerCached = this.itemsControl.GetScrollViewer();
return this.scrollViewerCached;
}
}
public bool IsScrolledToStart
{
get
{
if (ScrollViewer == null) // Visual tree not initialized yet
return false;
return ScrollViewer.VerticalOffset == 0;
}
}
public bool IsScrolledToEnd
{
get
{
if (itemsSourceTotalCount == null) {
// not scrolled to end of IEnumerable yet
return false;
}
// already scrolled to end of IEnumerable
int totalItems = itemsSourceTotalCount.Value;
return (ScrollViewer.VerticalOffset >= totalItems - ScrollViewer.ViewportHeight);
}
}
private int? itemsSourceTotalCount = null;
/// <summary> Items count of underlying IEnumerable. Null until scrolled to the end of IEnumerable. </summary>
public int? ItemsSourceTotalCount
{
get
{
return this.itemsSourceTotalCount;
}
}
private VirtualizingIEnumerable<T> itemsSource;
/// <summary> The collection that underlying ItemsControl sees. </summary>
public VirtualizingIEnumerable<T> ItemsSource
{
get
{
return itemsSource;
}
set
{
this.itemsSource = value;
addNextItems(this.itemsSource, initialItemsCount);
this.itemsControl.ItemsSource = value;
}
}
private void addNextItems(VirtualizingIEnumerable<T> sourceToAdd, int nItems)
{
sourceToAdd.AddNextItems(nItems);
if (!sourceToAdd.HasNext)
{
// all items from IEnumerable have been added
this.itemsSourceTotalCount = sourceToAdd.Count;
}
}
private void handleScroll(object sender, ScrollChangedEventArgs e)
{
if (e.VerticalChange > 0)
{
// scrolled to bottom
if (e.VerticalOffset >= this.itemsSource.Count - e.ViewportHeight)
{
addNextItems(this.itemsSource, (int)e.VerticalChange);
}
}
}
}
}

58
src/Main/Base/Project/Src/Services/Debugger/VirtualizingIEnumerable.cs

@ -0,0 +1,58 @@ @@ -0,0 +1,58 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Martin Koníček" email="martin.konicek@gmail.com"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace ICSharpCode.SharpDevelop.Debugging
{
/// <summary>
/// A wrapper around IEnumerable&lt;T&gt; with AddNextItems method for pulling additional items
/// from underlying IEnumerable&lt;T&gt;.
/// Can be used as source for <see cref="LazyItemsControl" />.
/// </summary>
public class VirtualizingIEnumerable<T> : ObservableCollection<T>
{
private IEnumerator<T> originalSourceEnumerator;
public VirtualizingIEnumerable(IEnumerable<T> originalSource)
{
if (originalSource == null)
throw new ArgumentNullException("originalSource");
this.originalSourceEnumerator = originalSource.GetEnumerator();
}
private bool hasNext = true;
/// <summary>
/// False if all items from underlying IEnumerable have already been added.
/// </summary>
public bool HasNext
{
get
{
return this.hasNext;
}
}
/// <summary>
/// Requests next <paramref name="count"/> items from underlying IEnumerable source and adds them to the collection.
/// </summary>
public void AddNextItems(int count)
{
for (int i = 0; i < count; i++)
{
if (!originalSourceEnumerator.MoveNext())
{
this.hasNext = false;
break;
}
this.Add(originalSourceEnumerator.Current);
}
}
}
}

67
src/Main/Base/Project/Src/Util/ScrollUtils.cs

@ -0,0 +1,67 @@ @@ -0,0 +1,67 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Martin Koníèek" email="martin.konicek@gmail.com"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace ICSharpCode.SharpDevelop
{
/// <summary>
/// Scrolling related helpers.
/// </summary>
public static class ScrollUtils
{
/// <summary>
/// Searches VisualTree of given object for a ScrollViewer.
/// </summary>
public static ScrollViewer GetScrollViewer(this DependencyObject o)
{
var scrollViewer = o as ScrollViewer;
if (scrollViewer != null) {
return scrollViewer;
}
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(o); i++)
{
var child = VisualTreeHelper.GetChild(o, i);
var result = GetScrollViewer(child);
if (result != null) {
return result;
}
}
return null;
}
/// <summary>
/// Scrolls ScrollViewer up by given offset.
/// </summary>
/// <param name="offset">Offset by which to scroll up. Should be positive.</param>
public static void ScrollUp(this ScrollViewer scrollViewer, double offset)
{
ScrollUtils.ScrollByVerticalOffset(scrollViewer, -offset);
}
/// <summary>
/// Scrolls ScrollViewer down by given offset.
/// </summary>
/// <param name="offset">Offset by which to scroll down. Should be positive.</param>
public static void ScrollDown(this ScrollViewer scrollViewer, double offset)
{
ScrollUtils.ScrollByVerticalOffset(scrollViewer, offset);
}
/// <summary>
/// Scrolls ScrollViewer by given vertical offset.
/// </summary>
public static void ScrollByVerticalOffset(this ScrollViewer scrollViewer, double offset)
{
scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset + offset);
}
}
}
Loading…
Cancel
Save