635 changed files with 194275 additions and 1576 deletions
@ -0,0 +1,46 @@ |
|||
/************************************************************************ |
|||
|
|||
Extended WPF Toolkit |
|||
|
|||
Copyright (C) 2010-2012 Xceed Software Inc. |
|||
|
|||
This program is provided to you under the terms of the Microsoft Public |
|||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
|||
|
|||
This program can be provided to you by Xceed Software Inc. under a |
|||
proprietary commercial license agreement for use in non-Open Source |
|||
projects. The commercial version of Extended WPF Toolkit also includes |
|||
priority technical support, commercial updates, and many additional |
|||
useful WPF controls if you license Xceed Business Suite for WPF. |
|||
|
|||
Visit http://xceed.com and follow @datagrid on Twitter.
|
|||
|
|||
**********************************************************************/ |
|||
|
|||
using Microsoft.Practices.Prism.Regions; |
|||
using Microsoft.Practices.Unity; |
|||
using Samples.Infrastructure; |
|||
using Samples.Infrastructure.Extensions; |
|||
using Samples.Modules.DataGrid.Views; |
|||
|
|||
namespace Samples.Modules.DataGrid |
|||
{ |
|||
public class DataGridModule : ModuleBase |
|||
{ |
|||
public DataGridModule( IUnityContainer container, IRegionManager regionManager ) |
|||
: base( container, regionManager ) |
|||
{ |
|||
} |
|||
|
|||
protected override void InitializeModule() |
|||
{ |
|||
RegionManager.RegisterViewWithRegion( RegionNames.NavigationRegion, typeof( NavigationView ) ); |
|||
} |
|||
|
|||
protected override void RegisterViewsAndTypes() |
|||
{ |
|||
Container.RegisterNavigationType( typeof( HomeView ) ); |
|||
Container.RegisterNavigationType( typeof( FullVersion ) ); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,72 @@ |
|||
/************************************************************************ |
|||
|
|||
Extended WPF Toolkit |
|||
|
|||
Copyright (C) 2010-2012 Xceed Software Inc. |
|||
|
|||
This program is provided to you under the terms of the Microsoft Public |
|||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
|||
|
|||
This program can be provided to you by Xceed Software Inc. under a |
|||
proprietary commercial license agreement for use in non-Open Source |
|||
projects. The commercial version of Extended WPF Toolkit also includes |
|||
priority technical support, commercial updates, and many additional |
|||
useful WPF controls if you license Xceed Business Suite for WPF. |
|||
|
|||
Visit http://xceed.com and follow @datagrid on Twitter.
|
|||
|
|||
**********************************************************************/ |
|||
|
|||
using System.Reflection; |
|||
using System.Runtime.InteropServices; |
|||
using System.Windows; |
|||
|
|||
// General Information about an assembly is controlled through the following
|
|||
// set of attributes. Change these attribute values to modify the information
|
|||
// associated with an assembly.
|
|||
[assembly: AssemblyTitle( "Extended WPF Toolkit DataGrid Sample" )] |
|||
[assembly: AssemblyDescription( "" )] |
|||
[assembly: AssemblyConfiguration( "" )] |
|||
[assembly: AssemblyCompany( "Xceed Software Inc." )] |
|||
[assembly: AssemblyProduct( "Extended WPF Toolkit DataGrid Sample" )] |
|||
[assembly: AssemblyCopyright( "Copyright © Xceed Software Inc. 2010-2012" )] |
|||
[assembly: AssemblyTrademark( "" )] |
|||
[assembly: AssemblyCulture( "" )] |
|||
|
|||
// Setting ComVisible to false makes the types in this assembly not visible
|
|||
// to COM components. If you need to access a type in this assembly from
|
|||
// COM, set the ComVisible attribute to true on that type.
|
|||
[assembly: ComVisible( false )] |
|||
|
|||
//In order to begin building localizable applications, set
|
|||
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
|
|||
//inside a <PropertyGroup>. For example, if you are using US english
|
|||
//in your source files, set the <UICulture> to en-US. Then uncomment
|
|||
//the NeutralResourceLanguage attribute below. Update the "en-US" in
|
|||
//the line below to match the UICulture setting in the project file.
|
|||
|
|||
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
|
|||
|
|||
|
|||
[assembly: ThemeInfo( |
|||
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
|
|||
//(used if a resource is not found in the page,
|
|||
// or application resource dictionaries)
|
|||
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
|
|||
//(used if a resource is not found in the page,
|
|||
// app, or any theme specific resource dictionaries)
|
|||
)] |
|||
|
|||
|
|||
// Version information for an assembly consists of the following four values:
|
|||
//
|
|||
// Major Version
|
|||
// Minor Version
|
|||
// Build Number
|
|||
// Revision
|
|||
//
|
|||
// You can specify all the values or you can default the Build and Revision Numbers
|
|||
// by using the '*' as shown below:
|
|||
// [assembly: AssemblyVersion("1.0.*")]
|
|||
[assembly: AssemblyVersion( "1.0.0.0" )] |
|||
[assembly: AssemblyFileVersion( "1.0.0.0" )] |
|||
@ -0,0 +1,116 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
|||
<PropertyGroup> |
|||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> |
|||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> |
|||
<ProductVersion>8.0.30703</ProductVersion> |
|||
<SchemaVersion>2.0</SchemaVersion> |
|||
<ProjectGuid>{129477D9-F413-495F-BE05-D049575BC16C}</ProjectGuid> |
|||
<OutputType>library</OutputType> |
|||
<AppDesignerFolder>Properties</AppDesignerFolder> |
|||
<RootNamespace>Samples.Modules.DataGrid</RootNamespace> |
|||
<AssemblyName>Samples.Modules.DataGrid</AssemblyName> |
|||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion> |
|||
<TargetFrameworkProfile>Client</TargetFrameworkProfile> |
|||
<FileAlignment>512</FileAlignment> |
|||
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> |
|||
<WarningLevel>4</WarningLevel> |
|||
</PropertyGroup> |
|||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> |
|||
<DebugSymbols>true</DebugSymbols> |
|||
<DebugType>full</DebugType> |
|||
<Optimize>false</Optimize> |
|||
<OutputPath>bin\Debug\</OutputPath> |
|||
<DefineConstants>DEBUG;TRACE</DefineConstants> |
|||
<ErrorReport>prompt</ErrorReport> |
|||
<WarningLevel>4</WarningLevel> |
|||
</PropertyGroup> |
|||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> |
|||
<DebugType>pdbonly</DebugType> |
|||
<Optimize>true</Optimize> |
|||
<OutputPath>bin\Release\</OutputPath> |
|||
<DefineConstants>TRACE</DefineConstants> |
|||
<ErrorReport>prompt</ErrorReport> |
|||
<WarningLevel>4</WarningLevel> |
|||
</PropertyGroup> |
|||
<ItemGroup> |
|||
<Reference Include="Microsoft.Practices.Prism"> |
|||
<HintPath>..\..\..\..\Libs\Prism\Microsoft.Practices.Prism.dll</HintPath> |
|||
</Reference> |
|||
<Reference Include="Microsoft.Practices.Unity"> |
|||
<HintPath>..\..\..\..\Libs\Prism\Microsoft.Practices.Unity.dll</HintPath> |
|||
</Reference> |
|||
<Reference Include="System" /> |
|||
<Reference Include="System.Data" /> |
|||
<Reference Include="System.Xml" /> |
|||
<Reference Include="Microsoft.CSharp" /> |
|||
<Reference Include="System.Core" /> |
|||
<Reference Include="System.Xml.Linq" /> |
|||
<Reference Include="System.Data.DataSetExtensions" /> |
|||
<Reference Include="System.Xaml"> |
|||
<RequiredTargetFramework>4.0</RequiredTargetFramework> |
|||
</Reference> |
|||
<Reference Include="WindowsBase" /> |
|||
<Reference Include="PresentationCore" /> |
|||
<Reference Include="PresentationFramework" /> |
|||
<Reference Include="Xceed.Wpf.DataGrid.Samples.SampleData"> |
|||
<HintPath>..\..\..\..\Libs\Xceed.Wpf.DataGrid.Samples.SampleData.dll</HintPath> |
|||
</Reference> |
|||
</ItemGroup> |
|||
<ItemGroup> |
|||
<Compile Include="DataGridModule.cs"> |
|||
<SubType>Code</SubType> |
|||
</Compile> |
|||
<Compile Include="Views\FullVersion.xaml.cs"> |
|||
<DependentUpon>FullVersion.xaml</DependentUpon> |
|||
</Compile> |
|||
<Compile Include="Views\HomeView.xaml.cs"> |
|||
<DependentUpon>HomeView.xaml</DependentUpon> |
|||
</Compile> |
|||
<Compile Include="Views\NavigationView.xaml.cs"> |
|||
<DependentUpon>NavigationView.xaml</DependentUpon> |
|||
</Compile> |
|||
</ItemGroup> |
|||
<ItemGroup> |
|||
<Compile Include="Properties\AssemblyInfo.cs"> |
|||
<SubType>Code</SubType> |
|||
</Compile> |
|||
<AppDesigner Include="Properties\" /> |
|||
</ItemGroup> |
|||
<ItemGroup> |
|||
<ProjectReference Include="..\..\..\Xceed.Wpf.DataGrid\Xceed.Wpf.DataGrid.csproj"> |
|||
<Project>{63648392-6CE9-4A60-96D4-F9FD718D29B0}</Project> |
|||
<Name>Xceed.Wpf.DataGrid</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\..\Samples.Infrastructure\Samples.Infrastructure.csproj"> |
|||
<Project>{A4A049A4-665A-4651-9046-7D06E9D0CCDC}</Project> |
|||
<Name>Samples.Infrastructure</Name> |
|||
</ProjectReference> |
|||
</ItemGroup> |
|||
<ItemGroup> |
|||
<Page Include="Views\FullVersion.xaml"> |
|||
<Generator>MSBuild:Compile</Generator> |
|||
<SubType>Designer</SubType> |
|||
</Page> |
|||
<Page Include="Views\HomeView.xaml"> |
|||
<Generator>MSBuild:Compile</Generator> |
|||
<SubType>Designer</SubType> |
|||
</Page> |
|||
<Page Include="Views\NavigationView.xaml"> |
|||
<Generator>MSBuild:Compile</Generator> |
|||
<SubType>Designer</SubType> |
|||
</Page> |
|||
</ItemGroup> |
|||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> |
|||
<PropertyGroup> |
|||
<PostBuildEvent>xcopy "$(TargetDir)*.*" "$(SolutionDir)Src\Samples\Samples\bin\$(ConfigurationName)\" /Y |
|||
xcopy "$(ProjectDir)Views" "$(SolutionDir)Src\Samples\Samples\bin\$(ConfigurationName)\Samples\$(ProjectName)\" /s /Y /I</PostBuildEvent> |
|||
</PropertyGroup> |
|||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. |
|||
Other similar extension points exist, see Microsoft.Common.targets. |
|||
<Target Name="BeforeBuild"> |
|||
</Target> |
|||
<Target Name="AfterBuild"> |
|||
</Target> |
|||
--> |
|||
</Project> |
|||
@ -0,0 +1,103 @@ |
|||
<!--********************************************************************* |
|||
|
|||
Extended WPF Toolkit |
|||
|
|||
Copyright (C) 2010-2012 Xceed Software Inc. |
|||
|
|||
This program is provided to you under the terms of the Microsoft Public |
|||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license |
|||
|
|||
This program can be provided to you by Xceed Software Inc. under a |
|||
proprietary commercial license agreement for use in non-Open Source |
|||
projects. The commercial version of Extended WPF Toolkit also includes |
|||
priority technical support, commercial updates, and many additional |
|||
useful WPF controls if you license Xceed Business Suite for WPF. |
|||
|
|||
Visit http://xceed.com and follow @datagrid on Twitter. |
|||
|
|||
********************************************************************--> |
|||
<sample:DemoView x:Class="Samples.Modules.DataGrid.Views.FullVersion" |
|||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" |
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
|||
xmlns:sample="clr-namespace:Samples.Infrastructure.Controls;assembly=Samples.Infrastructure" |
|||
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit" |
|||
xmlns:xcdg="http://schemas.xceed.com/wpf/xaml/datagrid" |
|||
xmlns:compModel="clr-namespace:System.ComponentModel;assembly=WindowsBase" |
|||
Title="Full Version" > |
|||
<StackPanel> |
|||
<RichTextBox IsReadOnly="True" IsDocumentEnabled="False" BorderThickness="0"> |
|||
<FlowDocument> |
|||
<Paragraph> |
|||
The full featured version of the DataGrid available commercially will provide |
|||
you with extended features like: |
|||
</Paragraph> |
|||
<List> |
|||
<ListItem> |
|||
<Paragraph>Master Details</Paragraph> |
|||
</ListItem> |
|||
<ListItem> |
|||
<Paragraph>Filter Row</Paragraph> |
|||
</ListItem> |
|||
<ListItem> |
|||
<Paragraph>Insertion Row</Paragraph> |
|||
</ListItem> |
|||
<ListItem> |
|||
<Paragraph>Excel Auto-Filtering</Paragraph> |
|||
</ListItem> |
|||
<ListItem> |
|||
<Paragraph>Column Chooser</Paragraph> |
|||
</ListItem> |
|||
<ListItem> |
|||
<Paragraph>CardView, CompactCardView</Paragraph> |
|||
</ListItem> |
|||
<ListItem> |
|||
<Paragraph>3DView, MultiSurfaceView</Paragraph> |
|||
</ListItem> |
|||
<ListItem> |
|||
<Paragraph>Statistical Functions and Summary row</Paragraph> |
|||
</ListItem> |
|||
<ListItem> |
|||
<Paragraph>Print, Print Preview</Paragraph> |
|||
</ListItem> |
|||
<ListItem> |
|||
<Paragraph>Export to Excel</Paragraph> |
|||
</ListItem> |
|||
<ListItem> |
|||
<Paragraph>Fixed Column Splitter UI element</Paragraph> |
|||
</ListItem> |
|||
<ListItem> |
|||
<Paragraph>Persist User Settings</Paragraph> |
|||
</ListItem> |
|||
<ListItem> |
|||
<Paragraph>Design time support in Visual Studio and Expression Blend</Paragraph> |
|||
</ListItem> |
|||
<ListItem> |
|||
<Paragraph>Comprehensive documentation fully integrated into Visual Studio</Paragraph> |
|||
</ListItem> |
|||
<ListItem> |
|||
<Paragraph>Includes a variety of VB.NET and C# sample applications to get you started</Paragraph> |
|||
</ListItem> |
|||
<ListItem> |
|||
<Paragraph>Office 2007 Themes: Blue, Black, and Silver</Paragraph> |
|||
</ListItem> |
|||
<ListItem> |
|||
<Paragraph>The Xceed Live Explorer theme</Paragraph> |
|||
</ListItem> |
|||
<ListItem> |
|||
<Paragraph>Includes Xceed 3D Views for WPF</Paragraph> |
|||
</ListItem> |
|||
<ListItem> |
|||
<Paragraph>And many more....</Paragraph> |
|||
</ListItem> |
|||
</List> |
|||
</FlowDocument> |
|||
</RichTextBox> |
|||
|
|||
<TextBlock Margin="0,20,0,0"> |
|||
<Hyperlink NavigateUri="http://www.xceed.com/Grid_WPF_Intro.html" RequestNavigate="Hyperlink_RequestNavigate"> |
|||
Click here for more details about the full featured DataGrid control. |
|||
</Hyperlink> |
|||
</TextBlock> |
|||
</StackPanel> |
|||
|
|||
</sample:DemoView> |
|||
@ -0,0 +1,46 @@ |
|||
/************************************************************************ |
|||
|
|||
Extended WPF Toolkit |
|||
|
|||
Copyright (C) 2010-2012 Xceed Software Inc. |
|||
|
|||
This program is provided to you under the terms of the Microsoft Public |
|||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
|||
|
|||
This program can be provided to you by Xceed Software Inc. under a |
|||
proprietary commercial license agreement for use in non-Open Source |
|||
projects. The commercial version of Extended WPF Toolkit also includes |
|||
priority technical support, commercial updates, and many additional |
|||
useful WPF controls if you license Xceed Business Suite for WPF. |
|||
|
|||
Visit http://xceed.com and follow @datagrid on Twitter.
|
|||
|
|||
**********************************************************************/ |
|||
|
|||
using Microsoft.Practices.Prism.Regions; |
|||
using Samples.Infrastructure.Controls; |
|||
using Xceed.Wpf.DataGrid.Samples.SampleData; |
|||
using System.Data; |
|||
using Xceed.Wpf.DataGrid; |
|||
using System.Diagnostics; |
|||
|
|||
namespace Samples.Modules.DataGrid.Views |
|||
{ |
|||
/// <summary>
|
|||
/// Interaction logic for FullVersion.xaml
|
|||
/// </summary>
|
|||
[RegionMemberLifetime( KeepAlive = false )] |
|||
public partial class FullVersion : DemoView |
|||
{ |
|||
public FullVersion() |
|||
{ |
|||
InitializeComponent(); |
|||
} |
|||
|
|||
private void Hyperlink_RequestNavigate( object sender, System.Windows.Navigation.RequestNavigateEventArgs e ) |
|||
{ |
|||
Process.Start( new ProcessStartInfo( e.Uri.AbsoluteUri ) ); |
|||
e.Handled = true; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,54 @@ |
|||
<!--********************************************************************* |
|||
|
|||
Extended WPF Toolkit |
|||
|
|||
Copyright (C) 2010-2012 Xceed Software Inc. |
|||
|
|||
This program is provided to you under the terms of the Microsoft Public |
|||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license |
|||
|
|||
This program can be provided to you by Xceed Software Inc. under a |
|||
proprietary commercial license agreement for use in non-Open Source |
|||
projects. The commercial version of Extended WPF Toolkit also includes |
|||
priority technical support, commercial updates, and many additional |
|||
useful WPF controls if you license Xceed Business Suite for WPF. |
|||
|
|||
Visit http://xceed.com and follow @datagrid on Twitter. |
|||
|
|||
********************************************************************--> |
|||
<sample:DemoView x:Class="Samples.Modules.DataGrid.Views.HomeView" |
|||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" |
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
|||
xmlns:sample="clr-namespace:Samples.Infrastructure.Controls;assembly=Samples.Infrastructure" |
|||
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit" |
|||
xmlns:xcdg="http://schemas.xceed.com/wpf/xaml/datagrid" |
|||
xmlns:compModel="clr-namespace:System.ComponentModel;assembly=WindowsBase" |
|||
Title="DataGrid" |
|||
x:Name="_demo"> |
|||
<sample:DemoView.Description> |
|||
The experience Xceed DataGrid for WPF provides centers on its Tableflow view, which lets you take advantage of a stunning, shaded appearance and capabilities such as inertial smooth scrolling and animated full-column reordering—which mimic the physics of real-life movement. Add to that the datagrid’s zero-lag data virtualization, and you have the fastest WPF datagrid around—in performance and feel. |
|||
|
|||
It's rock-solid and time-tested, so you can trust it in your most important applications. Constantly evolving—no other datagrid is updated as often—it has more features than any other offering and a flexible, extensible object model. It also provides unbeatable performance by handling millions of rows and thousands of columns, and integrates easily into any WPF app. It’s easy to understand why it’s the most-adopted WPF datagrid available and used by Microsoft in Visual Studio 2010 and by IBM U2 in SystemBuilder 4GL (SB+)! |
|||
|
|||
</sample:DemoView.Description> |
|||
<Grid> |
|||
<Grid.Resources> |
|||
<xcdg:DataGridCollectionViewSource x:Key="cvsOrders" |
|||
Source="{Binding ElementName=_demo, Path=Orders}"> |
|||
<xcdg:DataGridCollectionViewSource.GroupDescriptions> |
|||
<PropertyGroupDescription PropertyName="ShipCountry" /> |
|||
<PropertyGroupDescription PropertyName="ShipCity" /> |
|||
</xcdg:DataGridCollectionViewSource.GroupDescriptions> |
|||
</xcdg:DataGridCollectionViewSource> |
|||
</Grid.Resources> |
|||
|
|||
<xcdg:DataGridControl x:Name="_dataGrid" |
|||
MaxHeight="400" |
|||
ItemsSource="{Binding Source={StaticResource cvsOrders}}" > |
|||
<xcdg:DataGridControl.View> |
|||
<xcdg:TableflowView FixedColumnCount="2" /> |
|||
</xcdg:DataGridControl.View> |
|||
</xcdg:DataGridControl> |
|||
</Grid> |
|||
|
|||
</sample:DemoView> |
|||
@ -0,0 +1,47 @@ |
|||
/************************************************************************ |
|||
|
|||
Extended WPF Toolkit |
|||
|
|||
Copyright (C) 2010-2012 Xceed Software Inc. |
|||
|
|||
This program is provided to you under the terms of the Microsoft Public |
|||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
|||
|
|||
This program can be provided to you by Xceed Software Inc. under a |
|||
proprietary commercial license agreement for use in non-Open Source |
|||
projects. The commercial version of Extended WPF Toolkit also includes |
|||
priority technical support, commercial updates, and many additional |
|||
useful WPF controls if you license Xceed Business Suite for WPF. |
|||
|
|||
Visit http://xceed.com and follow @datagrid on Twitter.
|
|||
|
|||
**********************************************************************/ |
|||
|
|||
using Microsoft.Practices.Prism.Regions; |
|||
using Samples.Infrastructure.Controls; |
|||
using Xceed.Wpf.DataGrid.Samples.SampleData; |
|||
using System.Data; |
|||
using Xceed.Wpf.DataGrid; |
|||
|
|||
namespace Samples.Modules.DataGrid.Views |
|||
{ |
|||
/// <summary>
|
|||
/// Interaction logic for HomeView.xaml
|
|||
/// </summary>
|
|||
[RegionMemberLifetime( KeepAlive = false )] |
|||
public partial class HomeView : DemoView |
|||
{ |
|||
public HomeView() |
|||
{ |
|||
this.Orders = DataProvider.GetNorthwindDataSet().Tables[ "Orders" ]; |
|||
InitializeComponent(); |
|||
} |
|||
|
|||
public DataTable Orders |
|||
{ |
|||
get; |
|||
private set; |
|||
} |
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
<!--********************************************************************* |
|||
|
|||
Extended WPF Toolkit |
|||
|
|||
Copyright (C) 2010-2012 Xceed Software Inc. |
|||
|
|||
This program is provided to you under the terms of the Microsoft Public |
|||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license |
|||
|
|||
This program can be provided to you by Xceed Software Inc. under a |
|||
proprietary commercial license agreement for use in non-Open Source |
|||
projects. The commercial version of Extended WPF Toolkit also includes |
|||
priority technical support, commercial updates, and many additional |
|||
useful WPF controls if you license Xceed Business Suite for WPF. |
|||
|
|||
Visit http://xceed.com and follow @datagrid on Twitter. |
|||
|
|||
********************************************************************--> |
|||
<TreeViewItem x:Class="Samples.Modules.DataGrid.Views.NavigationView" |
|||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" |
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
|||
xmlns:views="clr-namespace:Samples.Modules.DataGrid.Views" |
|||
Header="DataGrid" Tag="{x:Type views:HomeView}" |
|||
Style="{StaticResource newFeature}"> |
|||
|
|||
<TreeViewItem.Resources> |
|||
<Style TargetType="views:NavigationView" BasedOn="{StaticResource {x:Type TreeViewItem}}" /> |
|||
</TreeViewItem.Resources> |
|||
|
|||
<TreeViewItem Header="Full Version" Tag="{x:Type views:FullVersion}" /> |
|||
|
|||
</TreeViewItem> |
|||
@ -0,0 +1,180 @@ |
|||
//------------------------------------------------------------------------------
|
|||
// <auto-generated>
|
|||
// This code was generated by a tool.
|
|||
// Runtime Version:4.0.30319.269
|
|||
//
|
|||
// Changes to this file may cause incorrect behavior and will be lost if
|
|||
// the code is regenerated.
|
|||
// </auto-generated>
|
|||
//------------------------------------------------------------------------------
|
|||
|
|||
namespace Samples.Modules.PropertyGrid.Views { |
|||
using System; |
|||
|
|||
|
|||
/// <summary>
|
|||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
|||
/// </summary>
|
|||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
|||
// class via a tool like ResGen or Visual Studio.
|
|||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
|||
// with the /str option, or rebuild your VS project.
|
|||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] |
|||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] |
|||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] |
|||
internal class DisplayLocalizationRes { |
|||
|
|||
private static global::System.Resources.ResourceManager resourceMan; |
|||
|
|||
private static global::System.Globalization.CultureInfo resourceCulture; |
|||
|
|||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] |
|||
internal DisplayLocalizationRes() { |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the cached ResourceManager instance used by this class.
|
|||
/// </summary>
|
|||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] |
|||
internal static global::System.Resources.ResourceManager ResourceManager { |
|||
get { |
|||
if (object.ReferenceEquals(resourceMan, null)) { |
|||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Samples.Modules.PropertyGrid.Views.DisplayLocalizationRes", typeof(DisplayLocalizationRes).Assembly); |
|||
resourceMan = temp; |
|||
} |
|||
return resourceMan; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Overrides the current thread's CurrentUICulture property for all
|
|||
/// resource lookups using this strongly typed resource class.
|
|||
/// </summary>
|
|||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] |
|||
internal static global::System.Globalization.CultureInfo Culture { |
|||
get { |
|||
return resourceCulture; |
|||
} |
|||
set { |
|||
resourceCulture = value; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Looks up a localized string similar to Details.
|
|||
/// </summary>
|
|||
internal static string DetailsCategory { |
|||
get { |
|||
return ResourceManager.GetString("DetailsCategory", resourceCulture); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Looks up a localized string similar to Favorite Actor 1 (No DisplayName).
|
|||
/// </summary>
|
|||
internal static string FavoriteActor1 { |
|||
get { |
|||
return ResourceManager.GetString("FavoriteActor1", resourceCulture); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Looks up a localized string similar to This property type is an enum where values has no DisplayName attributes. Theses values display are provided by ToString() method.
|
|||
/// </summary>
|
|||
internal static string FavoriteActor1Desc { |
|||
get { |
|||
return ResourceManager.GetString("FavoriteActor1Desc", resourceCulture); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Looks up a localized string similar to Favorite Actor 2 (With DisplayName).
|
|||
/// </summary>
|
|||
internal static string FavoriteActor2 { |
|||
get { |
|||
return ResourceManager.GetString("FavoriteActor2", resourceCulture); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Looks up a localized string similar to This property type is an enum where values are decorated with the ExtendedDisplayName attribute. Combined with the EnumDisplayNameConverter, this allow to customize display values.
|
|||
/// </summary>
|
|||
internal static string FavoriteActor2Desc { |
|||
get { |
|||
return ResourceManager.GetString("FavoriteActor2Desc", resourceCulture); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Looks up a localized string similar to Favorite Actor 3.
|
|||
/// </summary>
|
|||
internal static string FavoriteActor3 { |
|||
get { |
|||
return ResourceManager.GetString("FavoriteActor3", resourceCulture); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Looks up a localized string similar to "(Not listed)" enum value show that enum values can also be localized.
|
|||
/// </summary>
|
|||
internal static string FavoriteActor3Desc { |
|||
get { |
|||
return ResourceManager.GetString("FavoriteActor3Desc", resourceCulture); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Looks up a localized string similar to First Name.
|
|||
/// </summary>
|
|||
internal static string FirstName { |
|||
get { |
|||
return ResourceManager.GetString("FirstName", resourceCulture); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Looks up a localized string similar to First name of that person.
|
|||
/// </summary>
|
|||
internal static string FirstNameDesc { |
|||
get { |
|||
return ResourceManager.GetString("FirstNameDesc", resourceCulture); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Looks up a localized string similar to Information.
|
|||
/// </summary>
|
|||
internal static string InfoCategory { |
|||
get { |
|||
return ResourceManager.GetString("InfoCategory", resourceCulture); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Looks up a localized string similar to Last Name.
|
|||
/// </summary>
|
|||
internal static string LastName { |
|||
get { |
|||
return ResourceManager.GetString("LastName", resourceCulture); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Looks up a localized string similar to Usualy the Familly name of the person.
|
|||
/// </summary>
|
|||
internal static string LastNameDesc { |
|||
get { |
|||
return ResourceManager.GetString("LastNameDesc", resourceCulture); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Looks up a localized string similar to (No listed).
|
|||
/// </summary>
|
|||
internal static string NotListed { |
|||
get { |
|||
return ResourceManager.GetString("NotListed", resourceCulture); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,159 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<root> |
|||
<!-- |
|||
Microsoft ResX Schema |
|||
|
|||
Version 2.0 |
|||
|
|||
The primary goals of this format is to allow a simple XML format |
|||
that is mostly human readable. The generation and parsing of the |
|||
various data types are done through the TypeConverter classes |
|||
associated with the data types. |
|||
|
|||
Example: |
|||
|
|||
... ado.net/XML headers & schema ... |
|||
<resheader name="resmimetype">text/microsoft-resx</resheader> |
|||
<resheader name="version">2.0</resheader> |
|||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> |
|||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> |
|||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> |
|||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> |
|||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> |
|||
<value>[base64 mime encoded serialized .NET Framework object]</value> |
|||
</data> |
|||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> |
|||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> |
|||
<comment>This is a comment</comment> |
|||
</data> |
|||
|
|||
There are any number of "resheader" rows that contain simple |
|||
name/value pairs. |
|||
|
|||
Each data row contains a name, and value. The row also contains a |
|||
type or mimetype. Type corresponds to a .NET class that support |
|||
text/value conversion through the TypeConverter architecture. |
|||
Classes that don't support this are serialized and stored with the |
|||
mimetype set. |
|||
|
|||
The mimetype is used for serialized objects, and tells the |
|||
ResXResourceReader how to depersist the object. This is currently not |
|||
extensible. For a given mimetype the value must be set accordingly: |
|||
|
|||
Note - application/x-microsoft.net.object.binary.base64 is the format |
|||
that the ResXResourceWriter will generate, however the reader can |
|||
read any of the formats listed below. |
|||
|
|||
mimetype: application/x-microsoft.net.object.binary.base64 |
|||
value : The object must be serialized with |
|||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter |
|||
: and then encoded with base64 encoding. |
|||
|
|||
mimetype: application/x-microsoft.net.object.soap.base64 |
|||
value : The object must be serialized with |
|||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter |
|||
: and then encoded with base64 encoding. |
|||
|
|||
mimetype: application/x-microsoft.net.object.bytearray.base64 |
|||
value : The object must be serialized into a byte array |
|||
: using a System.ComponentModel.TypeConverter |
|||
: and then encoded with base64 encoding. |
|||
--> |
|||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> |
|||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> |
|||
<xsd:element name="root" msdata:IsDataSet="true"> |
|||
<xsd:complexType> |
|||
<xsd:choice maxOccurs="unbounded"> |
|||
<xsd:element name="metadata"> |
|||
<xsd:complexType> |
|||
<xsd:sequence> |
|||
<xsd:element name="value" type="xsd:string" minOccurs="0" /> |
|||
</xsd:sequence> |
|||
<xsd:attribute name="name" use="required" type="xsd:string" /> |
|||
<xsd:attribute name="type" type="xsd:string" /> |
|||
<xsd:attribute name="mimetype" type="xsd:string" /> |
|||
<xsd:attribute ref="xml:space" /> |
|||
</xsd:complexType> |
|||
</xsd:element> |
|||
<xsd:element name="assembly"> |
|||
<xsd:complexType> |
|||
<xsd:attribute name="alias" type="xsd:string" /> |
|||
<xsd:attribute name="name" type="xsd:string" /> |
|||
</xsd:complexType> |
|||
</xsd:element> |
|||
<xsd:element name="data"> |
|||
<xsd:complexType> |
|||
<xsd:sequence> |
|||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> |
|||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> |
|||
</xsd:sequence> |
|||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> |
|||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> |
|||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> |
|||
<xsd:attribute ref="xml:space" /> |
|||
</xsd:complexType> |
|||
</xsd:element> |
|||
<xsd:element name="resheader"> |
|||
<xsd:complexType> |
|||
<xsd:sequence> |
|||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> |
|||
</xsd:sequence> |
|||
<xsd:attribute name="name" type="xsd:string" use="required" /> |
|||
</xsd:complexType> |
|||
</xsd:element> |
|||
</xsd:choice> |
|||
</xsd:complexType> |
|||
</xsd:element> |
|||
</xsd:schema> |
|||
<resheader name="resmimetype"> |
|||
<value>text/microsoft-resx</value> |
|||
</resheader> |
|||
<resheader name="version"> |
|||
<value>2.0</value> |
|||
</resheader> |
|||
<resheader name="reader"> |
|||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> |
|||
</resheader> |
|||
<resheader name="writer"> |
|||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> |
|||
</resheader> |
|||
<data name="DetailsCategory" xml:space="preserve"> |
|||
<value>Détails</value> |
|||
</data> |
|||
<data name="FavoriteActor1" xml:space="preserve"> |
|||
<value>Acteur Favori 1 (Aucun DisplayName)</value> |
|||
</data> |
|||
<data name="FavoriteActor1Desc" xml:space="preserve"> |
|||
<value>Le type de cette propriété est un enum où les valeurs n'ont aucun attribut "DisplayName". Les valeur affiché sont retourné par la méthode ToString()</value> |
|||
</data> |
|||
<data name="FavoriteActor2" xml:space="preserve"> |
|||
<value>Acteur Favori 2 (Avec DisplayName)</value> |
|||
</data> |
|||
<data name="FavoriteActor2Desc" xml:space="preserve"> |
|||
<value>Le type de cette propriété est un enum où les valeurs sont décoré avec l'attribut "DisplayName". Les valeurs affichées sont celles spécifié par l'attribut ExtendedDisplayName</value> |
|||
</data> |
|||
<data name="FavoriteActor3" xml:space="preserve"> |
|||
<value>Acteur Favori 3</value> |
|||
</data> |
|||
<data name="FavoriteActor3Desc" xml:space="preserve"> |
|||
<value>La valeur "(Non proposé)" démontre que les valeur des enum peuvent aussi être localisée</value> |
|||
</data> |
|||
<data name="FirstName" xml:space="preserve"> |
|||
<value>Prénom</value> |
|||
</data> |
|||
<data name="FirstNameDesc" xml:space="preserve"> |
|||
<value>Prénom de la personne</value> |
|||
</data> |
|||
<data name="InfoCategory" xml:space="preserve"> |
|||
<value>Information</value> |
|||
</data> |
|||
<data name="LastName" xml:space="preserve"> |
|||
<value>Nom de famille</value> |
|||
</data> |
|||
<data name="LastNameDesc" xml:space="preserve"> |
|||
<value>Le nom de famille de la personne</value> |
|||
</data> |
|||
<data name="NotListed" xml:space="preserve"> |
|||
<value>(Non proposé)</value> |
|||
</data> |
|||
</root> |
|||
@ -0,0 +1,159 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<root> |
|||
<!-- |
|||
Microsoft ResX Schema |
|||
|
|||
Version 2.0 |
|||
|
|||
The primary goals of this format is to allow a simple XML format |
|||
that is mostly human readable. The generation and parsing of the |
|||
various data types are done through the TypeConverter classes |
|||
associated with the data types. |
|||
|
|||
Example: |
|||
|
|||
... ado.net/XML headers & schema ... |
|||
<resheader name="resmimetype">text/microsoft-resx</resheader> |
|||
<resheader name="version">2.0</resheader> |
|||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> |
|||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> |
|||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> |
|||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> |
|||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> |
|||
<value>[base64 mime encoded serialized .NET Framework object]</value> |
|||
</data> |
|||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> |
|||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> |
|||
<comment>This is a comment</comment> |
|||
</data> |
|||
|
|||
There are any number of "resheader" rows that contain simple |
|||
name/value pairs. |
|||
|
|||
Each data row contains a name, and value. The row also contains a |
|||
type or mimetype. Type corresponds to a .NET class that support |
|||
text/value conversion through the TypeConverter architecture. |
|||
Classes that don't support this are serialized and stored with the |
|||
mimetype set. |
|||
|
|||
The mimetype is used for serialized objects, and tells the |
|||
ResXResourceReader how to depersist the object. This is currently not |
|||
extensible. For a given mimetype the value must be set accordingly: |
|||
|
|||
Note - application/x-microsoft.net.object.binary.base64 is the format |
|||
that the ResXResourceWriter will generate, however the reader can |
|||
read any of the formats listed below. |
|||
|
|||
mimetype: application/x-microsoft.net.object.binary.base64 |
|||
value : The object must be serialized with |
|||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter |
|||
: and then encoded with base64 encoding. |
|||
|
|||
mimetype: application/x-microsoft.net.object.soap.base64 |
|||
value : The object must be serialized with |
|||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter |
|||
: and then encoded with base64 encoding. |
|||
|
|||
mimetype: application/x-microsoft.net.object.bytearray.base64 |
|||
value : The object must be serialized into a byte array |
|||
: using a System.ComponentModel.TypeConverter |
|||
: and then encoded with base64 encoding. |
|||
--> |
|||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> |
|||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> |
|||
<xsd:element name="root" msdata:IsDataSet="true"> |
|||
<xsd:complexType> |
|||
<xsd:choice maxOccurs="unbounded"> |
|||
<xsd:element name="metadata"> |
|||
<xsd:complexType> |
|||
<xsd:sequence> |
|||
<xsd:element name="value" type="xsd:string" minOccurs="0" /> |
|||
</xsd:sequence> |
|||
<xsd:attribute name="name" use="required" type="xsd:string" /> |
|||
<xsd:attribute name="type" type="xsd:string" /> |
|||
<xsd:attribute name="mimetype" type="xsd:string" /> |
|||
<xsd:attribute ref="xml:space" /> |
|||
</xsd:complexType> |
|||
</xsd:element> |
|||
<xsd:element name="assembly"> |
|||
<xsd:complexType> |
|||
<xsd:attribute name="alias" type="xsd:string" /> |
|||
<xsd:attribute name="name" type="xsd:string" /> |
|||
</xsd:complexType> |
|||
</xsd:element> |
|||
<xsd:element name="data"> |
|||
<xsd:complexType> |
|||
<xsd:sequence> |
|||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> |
|||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> |
|||
</xsd:sequence> |
|||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> |
|||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> |
|||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> |
|||
<xsd:attribute ref="xml:space" /> |
|||
</xsd:complexType> |
|||
</xsd:element> |
|||
<xsd:element name="resheader"> |
|||
<xsd:complexType> |
|||
<xsd:sequence> |
|||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> |
|||
</xsd:sequence> |
|||
<xsd:attribute name="name" type="xsd:string" use="required" /> |
|||
</xsd:complexType> |
|||
</xsd:element> |
|||
</xsd:choice> |
|||
</xsd:complexType> |
|||
</xsd:element> |
|||
</xsd:schema> |
|||
<resheader name="resmimetype"> |
|||
<value>text/microsoft-resx</value> |
|||
</resheader> |
|||
<resheader name="version"> |
|||
<value>2.0</value> |
|||
</resheader> |
|||
<resheader name="reader"> |
|||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> |
|||
</resheader> |
|||
<resheader name="writer"> |
|||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> |
|||
</resheader> |
|||
<data name="DetailsCategory" xml:space="preserve"> |
|||
<value>Details</value> |
|||
</data> |
|||
<data name="FavoriteActor1" xml:space="preserve"> |
|||
<value>Favorite Actor 1 (No DisplayName)</value> |
|||
</data> |
|||
<data name="FavoriteActor1Desc" xml:space="preserve"> |
|||
<value>This property type is an enum where values has no DisplayName attributes. Theses values display are provided by ToString() method</value> |
|||
</data> |
|||
<data name="FavoriteActor2" xml:space="preserve"> |
|||
<value>Favorite Actor 2 (With DisplayName)</value> |
|||
</data> |
|||
<data name="FavoriteActor2Desc" xml:space="preserve"> |
|||
<value>This property type is an enum where values are decorated with the ExtendedDisplayName attribute. Combined with the EnumDisplayNameConverter, this allow to customize display values</value> |
|||
</data> |
|||
<data name="FavoriteActor3" xml:space="preserve"> |
|||
<value>Favorite Actor 3</value> |
|||
</data> |
|||
<data name="FavoriteActor3Desc" xml:space="preserve"> |
|||
<value>"(Not listed)" enum value show that enum values can also be localized</value> |
|||
</data> |
|||
<data name="FirstName" xml:space="preserve"> |
|||
<value>First Name</value> |
|||
</data> |
|||
<data name="FirstNameDesc" xml:space="preserve"> |
|||
<value>First name of that person</value> |
|||
</data> |
|||
<data name="InfoCategory" xml:space="preserve"> |
|||
<value>Information</value> |
|||
</data> |
|||
<data name="LastName" xml:space="preserve"> |
|||
<value>Last Name</value> |
|||
</data> |
|||
<data name="LastNameDesc" xml:space="preserve"> |
|||
<value>Usualy the Familly name of the person</value> |
|||
</data> |
|||
<data name="NotListed" xml:space="preserve"> |
|||
<value>(No listed)</value> |
|||
</data> |
|||
</root> |
|||
@ -0,0 +1,118 @@ |
|||
<!--********************************************************************* |
|||
|
|||
Extended WPF Toolkit |
|||
|
|||
Copyright (C) 2010-2012 Xceed Software Inc. |
|||
|
|||
This program is provided to you under the terms of the Microsoft Public |
|||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license |
|||
|
|||
This program can be provided to you by Xceed Software Inc. under a |
|||
proprietary commercial license agreement for use in non-Open Source |
|||
projects. The commercial version of Extended WPF Toolkit also includes |
|||
priority technical support, commercial updates, and many additional |
|||
useful WPF controls if you license Xceed Business Suite for WPF. |
|||
|
|||
Visit http://xceed.com and follow @datagrid on Twitter. |
|||
|
|||
********************************************************************--> |
|||
<sample:DemoView x:Class="Samples.Modules.Text.Views.AutoSelectTextBoxView" |
|||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" |
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
|||
xmlns:sample="clr-namespace:Samples.Infrastructure.Controls;assembly=Samples.Infrastructure" |
|||
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit" |
|||
Title="AutoSelectTextBox" |
|||
Description="The AutoSelectTextBox allow to select the text content when the control get the focus. It also allow to affect the Focus navigation behavior winthin the control"> |
|||
<StackPanel> |
|||
<StackPanel.Resources> |
|||
<Style TargetType="{x:Type xctk:AutoSelectTextBox}"> |
|||
<Setter Property="Margin" Value="5"/> |
|||
<Setter Property="AutoSelectBehavior" Value="{Binding SelectedItem, ElementName=_autoSelectBehavior}"/> |
|||
<Setter Property="AutoMoveFocus" Value="{Binding IsChecked, ElementName=_autoMoveFocus}"/> |
|||
</Style> |
|||
</StackPanel.Resources> |
|||
|
|||
<!-- FEATURES GROUP BOX --> |
|||
<GroupBox Header="Features" > |
|||
<Grid Margin="5"> |
|||
<Grid.ColumnDefinitions> |
|||
<ColumnDefinition /> |
|||
<ColumnDefinition /> |
|||
</Grid.ColumnDefinitions> |
|||
<StackPanel Orientation="Horizontal" Grid.Column="0"> |
|||
<TextBlock Grid.Row="0" Grid.Column="0" Text="AutoSelectBehavior: " VerticalAlignment="Center" /> |
|||
<ComboBox Grid.Row="0" Grid.Column="1" x:Name="_autoSelectBehavior" SelectedIndex="1" Width="100" VerticalAlignment="Center"> |
|||
<x:StaticExtension Member="xctk:AutoSelectBehavior.Never" /> |
|||
<x:StaticExtension Member="xctk:AutoSelectBehavior.OnFocus" /> |
|||
</ComboBox> |
|||
</StackPanel> |
|||
<StackPanel Orientation="Horizontal" Grid.Column="1"> |
|||
<TextBlock Grid.Row="0" Grid.Column="2" Text="AutoMoveFocus: " VerticalAlignment="Center" /> |
|||
<CheckBox Grid.Row="0" Grid.Column="3" x:Name="_autoMoveFocus" IsChecked="True" VerticalAlignment="Center"/> |
|||
</StackPanel> |
|||
</Grid> |
|||
</GroupBox> |
|||
|
|||
<StackPanel> |
|||
<TextBlock Text="Usage:" Style="{StaticResource Header}"/> |
|||
<RichTextBox IsReadOnly="True" BorderThickness="0"> |
|||
<FlowDocument> |
|||
<Paragraph> |
|||
<Bold>AutoSelectBehavior:</Bold> |
|||
<LineBreak/> |
|||
Controled by the "AutoSelectBehavior" property, the content of the AutoSelectTextBox will be selected or not when the control get the focus. |
|||
<LineBreak/> |
|||
<LineBreak/> |
|||
<Bold>AutoMoveFocus:</Bold> |
|||
<LineBreak/> |
|||
<Italic>Effect with "MaxLength" property:</Italic> |
|||
<LineBreak/> |
|||
<LineBreak/> |
|||
Setting the "MaxLenght" of the text box allow the focus to move from the AutoSelectTextBox once the max lenght has been reached. |
|||
In the following "Telephone Number" fields, the "MaxLenght" property of the control has been set to 3, 3 and 4, respectively |
|||
</Paragraph> |
|||
</FlowDocument> |
|||
</RichTextBox> |
|||
|
|||
<!-- PHONE NUMBER FIELDS --> |
|||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center"> |
|||
<TextBlock Text="(" VerticalAlignment="Center"/> |
|||
<xctk:AutoSelectTextBox MaxLength="3" Width="30" Text="555"/> |
|||
<TextBlock Text=")" VerticalAlignment="Center"/> |
|||
<xctk:AutoSelectTextBox MaxLength="3" Width="30" Text="555"/> |
|||
<TextBlock Text="-" VerticalAlignment="Center"/> |
|||
<xctk:AutoSelectTextBox MaxLength="4" Width="40" Text="5555"/> |
|||
</StackPanel> |
|||
<RichTextBox IsReadOnly="True" BorderThickness="0"> |
|||
<FlowDocument> |
|||
<Paragraph> |
|||
<Italic>Effect with Arrow keys</Italic> |
|||
<LineBreak/> |
|||
<LineBreak/> |
|||
The "AutoMoveFocus" at true also allow to navigate the focus thru the controls using the arrow keys to move the focus up, down, left or right. |
|||
You are no longer limited to the "left-right" scenario of the "Tab, Shift-Tab" keys. |
|||
</Paragraph> |
|||
</FlowDocument> |
|||
</RichTextBox> |
|||
|
|||
<!-- TEXTBOX MATRIX --> |
|||
<StackPanel Orientation="Vertical" HorizontalAlignment="Center"> |
|||
<StackPanel Orientation="Horizontal"> |
|||
<xctk:AutoSelectTextBox Text="Text1" Width="100" /> |
|||
<xctk:AutoSelectTextBox Text="Text2" Width="100"/> |
|||
<xctk:AutoSelectTextBox Text="Text3" Width="100"/> |
|||
</StackPanel> |
|||
<StackPanel Orientation="Horizontal"> |
|||
<xctk:AutoSelectTextBox Text="Text4" Width="100"/> |
|||
<xctk:AutoSelectTextBox Text="Text5" Width="100"/> |
|||
<xctk:AutoSelectTextBox Text="Text6" Width="100"/> |
|||
</StackPanel> |
|||
<StackPanel Orientation="Horizontal"> |
|||
<xctk:AutoSelectTextBox Text="Text7" Width="100"/> |
|||
<xctk:AutoSelectTextBox Text="Text8" Width="100"/> |
|||
<xctk:AutoSelectTextBox Text="Text9" Width="100"/> |
|||
</StackPanel> |
|||
</StackPanel> |
|||
</StackPanel> |
|||
</StackPanel> |
|||
</sample:DemoView> |
|||
@ -0,0 +1,31 @@ |
|||
/************************************************************************ |
|||
|
|||
Extended WPF Toolkit |
|||
|
|||
Copyright (C) 2010-2012 Xceed Software Inc. |
|||
|
|||
This program is provided to you under the terms of the Microsoft Public |
|||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
|||
|
|||
This program can be provided to you by Xceed Software Inc. under a |
|||
proprietary commercial license agreement for use in non-Open Source |
|||
projects. The commercial version of Extended WPF Toolkit also includes |
|||
priority technical support, commercial updates, and many additional |
|||
useful WPF controls if you license Xceed Business Suite for WPF. |
|||
|
|||
Visit http://xceed.com and follow @datagrid on Twitter.
|
|||
|
|||
**********************************************************************/ |
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Text; |
|||
|
|||
namespace Xceed.Wpf.Toolkit |
|||
{ |
|||
public enum AutoSelectBehavior |
|||
{ |
|||
Never, |
|||
OnFocus |
|||
} |
|||
} |
|||
@ -0,0 +1,301 @@ |
|||
/************************************************************************ |
|||
|
|||
Extended WPF Toolkit |
|||
|
|||
Copyright (C) 2010-2012 Xceed Software Inc. |
|||
|
|||
This program is provided to you under the terms of the Microsoft Public |
|||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
|||
|
|||
This program can be provided to you by Xceed Software Inc. under a |
|||
proprietary commercial license agreement for use in non-Open Source |
|||
projects. The commercial version of Extended WPF Toolkit also includes |
|||
priority technical support, commercial updates, and many additional |
|||
useful WPF controls if you license Xceed Business Suite for WPF. |
|||
|
|||
Visit http://xceed.com and follow @datagrid on Twitter.
|
|||
|
|||
**********************************************************************/ |
|||
|
|||
using System.Windows.Controls; |
|||
using System.Windows.Input; |
|||
using System.Windows; |
|||
using System.Windows.Automation; |
|||
using Xceed.Wpf.Toolkit.Core.Utilities; |
|||
|
|||
namespace Xceed.Wpf.Toolkit |
|||
{ |
|||
public class AutoSelectTextBox : TextBox |
|||
{ |
|||
static AutoSelectTextBox() |
|||
{ |
|||
AutomationProperties.AutomationIdProperty.OverrideMetadata( typeof( AutoSelectTextBox ), new UIPropertyMetadata( "AutoSelectTextBox" ) ); |
|||
} |
|||
|
|||
#region AutoSelectBehavior PROPERTY
|
|||
|
|||
public AutoSelectBehavior AutoSelectBehavior |
|||
{ |
|||
get |
|||
{ |
|||
return ( AutoSelectBehavior )GetValue( AutoSelectBehaviorProperty ); |
|||
} |
|||
set |
|||
{ |
|||
SetValue( AutoSelectBehaviorProperty, value ); |
|||
} |
|||
} |
|||
|
|||
public static readonly DependencyProperty AutoSelectBehaviorProperty = |
|||
DependencyProperty.Register( "AutoSelectBehavior", typeof( AutoSelectBehavior ), typeof( AutoSelectTextBox ), |
|||
new UIPropertyMetadata( AutoSelectBehavior.Never ) ); |
|||
|
|||
#endregion AutoSelectBehavior PROPERTY
|
|||
|
|||
#region AutoMoveFocus PROPERTY
|
|||
|
|||
public bool AutoMoveFocus |
|||
{ |
|||
get |
|||
{ |
|||
return ( bool )GetValue( AutoMoveFocusProperty ); |
|||
} |
|||
set |
|||
{ |
|||
SetValue( AutoMoveFocusProperty, value ); |
|||
} |
|||
} |
|||
|
|||
public static readonly DependencyProperty AutoMoveFocusProperty = |
|||
DependencyProperty.Register( "AutoMoveFocus", typeof( bool ), typeof( AutoSelectTextBox ), new UIPropertyMetadata( false ) ); |
|||
|
|||
#endregion AutoMoveFocus PROPERTY
|
|||
|
|||
#region QueryMoveFocus EVENT
|
|||
|
|||
public static readonly RoutedEvent QueryMoveFocusEvent = EventManager.RegisterRoutedEvent( "QueryMoveFocus", |
|||
RoutingStrategy.Bubble, |
|||
typeof( QueryMoveFocusEventHandler ), |
|||
typeof( AutoSelectTextBox ) ); |
|||
#endregion QueryMoveFocus EVENT
|
|||
|
|||
protected override void OnPreviewKeyDown( KeyEventArgs e ) |
|||
{ |
|||
if( !this.AutoMoveFocus ) |
|||
{ |
|||
base.OnPreviewKeyDown( e ); |
|||
return; |
|||
} |
|||
|
|||
if( ( e.Key == Key.Left ) |
|||
&& ( ( Keyboard.Modifiers == ModifierKeys.None ) |
|||
|| ( Keyboard.Modifiers == ModifierKeys.Control ) ) ) |
|||
{ |
|||
e.Handled = this.MoveFocusLeft(); |
|||
} |
|||
|
|||
if( ( e.Key == Key.Right ) |
|||
&& ( ( Keyboard.Modifiers == ModifierKeys.None ) |
|||
|| ( Keyboard.Modifiers == ModifierKeys.Control ) ) ) |
|||
{ |
|||
e.Handled = this.MoveFocusRight(); |
|||
} |
|||
|
|||
if( ( ( e.Key == Key.Up ) || ( e.Key == Key.PageUp ) ) |
|||
&& ( ( Keyboard.Modifiers == ModifierKeys.None ) |
|||
|| ( Keyboard.Modifiers == ModifierKeys.Control ) ) ) |
|||
{ |
|||
e.Handled = this.MoveFocusUp(); |
|||
} |
|||
|
|||
if( ( ( e.Key == Key.Down ) || ( e.Key == Key.PageDown ) ) |
|||
&& ( ( Keyboard.Modifiers == ModifierKeys.None ) |
|||
|| ( Keyboard.Modifiers == ModifierKeys.Control ) ) ) |
|||
{ |
|||
e.Handled = this.MoveFocusDown(); |
|||
} |
|||
|
|||
base.OnPreviewKeyDown( e ); |
|||
} |
|||
|
|||
protected override void OnPreviewGotKeyboardFocus( KeyboardFocusChangedEventArgs e ) |
|||
{ |
|||
base.OnPreviewGotKeyboardFocus( e ); |
|||
|
|||
if( this.AutoSelectBehavior == AutoSelectBehavior.OnFocus ) |
|||
{ |
|||
// If the focus was not in one of our child ( or popup ), we select all the text.
|
|||
if( !TreeHelper.IsDescendantOf( e.OldFocus as DependencyObject, this ) ) |
|||
this.SelectAll(); |
|||
} |
|||
} |
|||
|
|||
protected override void OnPreviewMouseLeftButtonDown( MouseButtonEventArgs e ) |
|||
{ |
|||
base.OnPreviewMouseLeftButtonDown( e ); |
|||
|
|||
if( this.AutoSelectBehavior == AutoSelectBehavior.Never ) |
|||
return; |
|||
|
|||
if( this.IsKeyboardFocusWithin == false ) |
|||
{ |
|||
this.Focus(); |
|||
e.Handled = true; |
|||
} |
|||
} |
|||
|
|||
protected override void OnTextChanged( TextChangedEventArgs e ) |
|||
{ |
|||
base.OnTextChanged( e ); |
|||
|
|||
if( !this.AutoMoveFocus ) |
|||
return; |
|||
|
|||
if( ( this.Text.Length != 0 ) |
|||
&& ( this.Text.Length == this.MaxLength ) |
|||
&& ( this.CaretIndex == this.MaxLength ) ) |
|||
{ |
|||
if( this.CanMoveFocus( FocusNavigationDirection.Right, true ) == true ) |
|||
{ |
|||
FocusNavigationDirection direction = ( this.FlowDirection == FlowDirection.LeftToRight ) |
|||
? FocusNavigationDirection.Right |
|||
: FocusNavigationDirection.Left; |
|||
|
|||
this.MoveFocus( new TraversalRequest( direction ) ); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private bool CanMoveFocus( FocusNavigationDirection direction, bool reachedMax ) |
|||
{ |
|||
QueryMoveFocusEventArgs e = new QueryMoveFocusEventArgs( direction, reachedMax ); |
|||
this.RaiseEvent( e ); |
|||
return e.CanMoveFocus; |
|||
} |
|||
|
|||
private bool MoveFocusLeft() |
|||
{ |
|||
if( this.FlowDirection == FlowDirection.LeftToRight ) |
|||
{ |
|||
//occurs only if the cursor is at the beginning of the text
|
|||
if( ( this.CaretIndex == 0 ) && ( this.SelectionLength == 0 ) ) |
|||
{ |
|||
if( ComponentCommands.MoveFocusBack.CanExecute( null, this ) ) |
|||
{ |
|||
ComponentCommands.MoveFocusBack.Execute( null, this ); |
|||
return true; |
|||
} |
|||
else if( this.CanMoveFocus( FocusNavigationDirection.Left, false ) ) |
|||
{ |
|||
this.MoveFocus( new TraversalRequest( FocusNavigationDirection.Left ) ); |
|||
return true; |
|||
} |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
//occurs only if the cursor is at the end of the text
|
|||
if( ( this.CaretIndex == this.Text.Length ) && ( this.SelectionLength == 0 ) ) |
|||
{ |
|||
if( ComponentCommands.MoveFocusBack.CanExecute( null, this ) ) |
|||
{ |
|||
ComponentCommands.MoveFocusBack.Execute( null, this ); |
|||
return true; |
|||
} |
|||
else if( this.CanMoveFocus( FocusNavigationDirection.Left, false ) ) |
|||
{ |
|||
this.MoveFocus( new TraversalRequest( FocusNavigationDirection.Left ) ); |
|||
return true; |
|||
} |
|||
} |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
private bool MoveFocusRight() |
|||
{ |
|||
if( this.FlowDirection == FlowDirection.LeftToRight ) |
|||
{ |
|||
//occurs only if the cursor is at the beginning of the text
|
|||
if( ( this.CaretIndex == this.Text.Length ) && ( this.SelectionLength == 0 ) ) |
|||
{ |
|||
if( ComponentCommands.MoveFocusForward.CanExecute( null, this ) ) |
|||
{ |
|||
ComponentCommands.MoveFocusForward.Execute( null, this ); |
|||
return true; |
|||
} |
|||
else if( this.CanMoveFocus( FocusNavigationDirection.Right, false ) ) |
|||
{ |
|||
this.MoveFocus( new TraversalRequest( FocusNavigationDirection.Right ) ); |
|||
return true; |
|||
} |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
//occurs only if the cursor is at the end of the text
|
|||
if( ( this.CaretIndex == 0 ) && ( this.SelectionLength == 0 ) ) |
|||
{ |
|||
if( ComponentCommands.MoveFocusForward.CanExecute( null, this ) ) |
|||
{ |
|||
ComponentCommands.MoveFocusForward.Execute( null, this ); |
|||
return true; |
|||
} |
|||
else if( this.CanMoveFocus( FocusNavigationDirection.Right, false ) ) |
|||
{ |
|||
this.MoveFocus( new TraversalRequest( FocusNavigationDirection.Right ) ); |
|||
return true; |
|||
} |
|||
} |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
private bool MoveFocusUp() |
|||
{ |
|||
int lineNumber = this.GetLineIndexFromCharacterIndex( this.SelectionStart ); |
|||
|
|||
//occurs only if the cursor is on the first line
|
|||
if( lineNumber == 0 ) |
|||
{ |
|||
if( ComponentCommands.MoveFocusUp.CanExecute( null, this ) ) |
|||
{ |
|||
ComponentCommands.MoveFocusUp.Execute( null, this ); |
|||
return true; |
|||
} |
|||
else if( this.CanMoveFocus( FocusNavigationDirection.Up, false ) ) |
|||
{ |
|||
this.MoveFocus( new TraversalRequest( FocusNavigationDirection.Up ) ); |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
private bool MoveFocusDown() |
|||
{ |
|||
int lineNumber = this.GetLineIndexFromCharacterIndex( this.SelectionStart ); |
|||
|
|||
//occurs only if the cursor is on the first line
|
|||
if( lineNumber == ( this.LineCount - 1 ) ) |
|||
{ |
|||
if( ComponentCommands.MoveFocusDown.CanExecute( null, this ) ) |
|||
{ |
|||
ComponentCommands.MoveFocusDown.Execute( null, this ); |
|||
return true; |
|||
} |
|||
else if( this.CanMoveFocus( FocusNavigationDirection.Down, false ) ) |
|||
{ |
|||
this.MoveFocus( new TraversalRequest( FocusNavigationDirection.Down ) ); |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,76 @@ |
|||
/************************************************************************ |
|||
|
|||
Extended WPF Toolkit |
|||
|
|||
Copyright (C) 2010-2012 Xceed Software Inc. |
|||
|
|||
This program is provided to you under the terms of the Microsoft Public |
|||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
|||
|
|||
This program can be provided to you by Xceed Software Inc. under a |
|||
proprietary commercial license agreement for use in non-Open Source |
|||
projects. The commercial version of Extended WPF Toolkit also includes |
|||
priority technical support, commercial updates, and many additional |
|||
useful WPF controls if you license Xceed Business Suite for WPF. |
|||
|
|||
Visit http://xceed.com and follow @datagrid on Twitter.
|
|||
|
|||
**********************************************************************/ |
|||
|
|||
using System.Windows; |
|||
using System.Windows.Input; |
|||
|
|||
namespace Xceed.Wpf.Toolkit |
|||
{ |
|||
[System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Design", "CA1003:UseGenericEventHandlerInstances" )] |
|||
public delegate void QueryMoveFocusEventHandler( object sender, QueryMoveFocusEventArgs e ); |
|||
|
|||
public class QueryMoveFocusEventArgs : RoutedEventArgs |
|||
{ |
|||
//default CTOR private to prevent its usage.
|
|||
private QueryMoveFocusEventArgs() |
|||
{ |
|||
} |
|||
|
|||
//internal to prevent anybody from building this type of event.
|
|||
internal QueryMoveFocusEventArgs( FocusNavigationDirection direction, bool reachedMaxLength ) |
|||
: base( AutoSelectTextBox.QueryMoveFocusEvent ) |
|||
{ |
|||
m_navigationDirection = direction; |
|||
m_reachedMaxLength = reachedMaxLength; |
|||
} |
|||
|
|||
public FocusNavigationDirection FocusNavigationDirection |
|||
{ |
|||
get |
|||
{ |
|||
return m_navigationDirection; |
|||
} |
|||
} |
|||
|
|||
public bool ReachedMaxLength |
|||
{ |
|||
get |
|||
{ |
|||
return m_reachedMaxLength; |
|||
} |
|||
} |
|||
|
|||
public bool CanMoveFocus |
|||
{ |
|||
get |
|||
{ |
|||
return m_canMove; |
|||
} |
|||
set |
|||
{ |
|||
m_canMove = value; |
|||
} |
|||
} |
|||
|
|||
private FocusNavigationDirection m_navigationDirection; |
|||
private bool m_reachedMaxLength; |
|||
private bool m_canMove = true; //defaults to true... if nobody does nothing, then its capable of moving focus.
|
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
/************************************************************************ |
|||
|
|||
Extended WPF Toolkit |
|||
|
|||
Copyright (C) 2010-2012 Xceed Software Inc. |
|||
|
|||
This program is provided to you under the terms of the Microsoft Public |
|||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
|||
|
|||
This program can be provided to you by Xceed Software Inc. under a |
|||
proprietary commercial license agreement for use in non-Open Source |
|||
projects. The commercial version of Extended WPF Toolkit also includes |
|||
priority technical support, commercial updates, and many additional |
|||
useful WPF controls if you license Xceed Business Suite for WPF. |
|||
|
|||
Visit http://xceed.com and follow @datagrid on Twitter.
|
|||
|
|||
**********************************************************************/ |
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
|
|||
namespace Xceed.Wpf.Toolkit.Core.Input |
|||
{ |
|||
public interface IValidateInput |
|||
{ |
|||
event InputValidationErrorEventHandler InputValidationError; |
|||
void CommitInput(); |
|||
} |
|||
} |
|||
@ -0,0 +1,46 @@ |
|||
/************************************************************************ |
|||
|
|||
Extended WPF Toolkit |
|||
|
|||
Copyright (C) 2010-2012 Xceed Software Inc. |
|||
|
|||
This program is provided to you under the terms of the Microsoft Public |
|||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
|||
|
|||
This program can be provided to you by Xceed Software Inc. under a |
|||
proprietary commercial license agreement for use in non-Open Source |
|||
projects. The commercial version of Extended WPF Toolkit also includes |
|||
priority technical support, commercial updates, and many additional |
|||
useful WPF controls if you license Xceed Business Suite for WPF. |
|||
|
|||
Visit http://xceed.com and follow @datagrid on Twitter.
|
|||
|
|||
**********************************************************************/ |
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
|
|||
namespace Xceed.Wpf.Toolkit.Core.Input |
|||
{ |
|||
public delegate void InputValidationErrorEventHandler( object sender, InputValidationErrorEventArgs e ); |
|||
|
|||
public class InputValidationErrorEventArgs : EventArgs |
|||
{ |
|||
public InputValidationErrorEventArgs( string errorMsg ) |
|||
{ |
|||
_errorMessage = errorMsg; |
|||
} |
|||
|
|||
public string ErrorMessage |
|||
{ |
|||
get |
|||
{ |
|||
return _errorMessage; |
|||
} |
|||
} |
|||
|
|||
private string _errorMessage; |
|||
} |
|||
} |
|||
@ -0,0 +1,57 @@ |
|||
/************************************************************************ |
|||
|
|||
Extended WPF Toolkit |
|||
|
|||
Copyright (C) 2010-2012 Xceed Software Inc. |
|||
|
|||
This program is provided to you under the terms of the Microsoft Public |
|||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
|||
|
|||
This program can be provided to you by Xceed Software Inc. under a |
|||
proprietary commercial license agreement for use in non-Open Source |
|||
projects. The commercial version of Extended WPF Toolkit also includes |
|||
priority technical support, commercial updates, and many additional |
|||
useful WPF controls if you license Xceed Business Suite for WPF. |
|||
|
|||
Visit http://xceed.com and follow @datagrid on Twitter.
|
|||
|
|||
**********************************************************************/ |
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Windows.Controls; |
|||
|
|||
namespace Xceed.Wpf.Toolkit.Primitives |
|||
{ |
|||
internal class CachedTextInfo : ICloneable |
|||
{ |
|||
private CachedTextInfo( string text, int caretIndex, int selectionStart, int selectionLength ) |
|||
{ |
|||
this.Text = text; |
|||
this.CaretIndex = caretIndex; |
|||
this.SelectionStart = selectionStart; |
|||
this.SelectionLength = selectionLength; |
|||
} |
|||
|
|||
public CachedTextInfo( TextBox textBox ) |
|||
: this( textBox.Text, textBox.CaretIndex, textBox.SelectionStart, textBox.SelectionLength ) |
|||
{ |
|||
} |
|||
|
|||
public string Text { get; private set; } |
|||
public int CaretIndex { get; private set; } |
|||
public int SelectionStart { get; private set; } |
|||
public int SelectionLength { get; private set; } |
|||
|
|||
#region ICloneable Members
|
|||
|
|||
public object Clone() |
|||
{ |
|||
return new CachedTextInfo( this.Text, this.CaretIndex, this.SelectionStart, this.SelectionLength ); |
|||
} |
|||
|
|||
#endregion
|
|||
} |
|||
} |
|||
File diff suppressed because it is too large
@ -0,0 +1,57 @@ |
|||
/************************************************************************ |
|||
|
|||
Extended WPF Toolkit |
|||
|
|||
Copyright (C) 2010-2012 Xceed Software Inc. |
|||
|
|||
This program is provided to you under the terms of the Microsoft Public |
|||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
|||
|
|||
This program can be provided to you by Xceed Software Inc. under a |
|||
proprietary commercial license agreement for use in non-Open Source |
|||
projects. The commercial version of Extended WPF Toolkit also includes |
|||
priority technical support, commercial updates, and many additional |
|||
useful WPF controls if you license Xceed Business Suite for WPF. |
|||
|
|||
Visit http://xceed.com and follow @datagrid on Twitter.
|
|||
|
|||
**********************************************************************/ |
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Text; |
|||
|
|||
namespace Xceed.Wpf.Toolkit.Core |
|||
{ |
|||
public class QueryTextFromValueEventArgs : EventArgs |
|||
{ |
|||
public QueryTextFromValueEventArgs( object value, string text ) |
|||
{ |
|||
m_value = value; |
|||
m_text = text; |
|||
} |
|||
|
|||
#region Value Property
|
|||
|
|||
private object m_value; |
|||
|
|||
public object Value |
|||
{ |
|||
get { return m_value; } |
|||
} |
|||
|
|||
#endregion Value Property
|
|||
|
|||
#region Text Property
|
|||
|
|||
private string m_text; |
|||
|
|||
public string Text |
|||
{ |
|||
get { return m_text; } |
|||
set { m_text = value; } |
|||
} |
|||
|
|||
#endregion Text Property
|
|||
} |
|||
} |
|||
@ -0,0 +1,70 @@ |
|||
/************************************************************************ |
|||
|
|||
Extended WPF Toolkit |
|||
|
|||
Copyright (C) 2010-2012 Xceed Software Inc. |
|||
|
|||
This program is provided to you under the terms of the Microsoft Public |
|||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
|||
|
|||
This program can be provided to you by Xceed Software Inc. under a |
|||
proprietary commercial license agreement for use in non-Open Source |
|||
projects. The commercial version of Extended WPF Toolkit also includes |
|||
priority technical support, commercial updates, and many additional |
|||
useful WPF controls if you license Xceed Business Suite for WPF. |
|||
|
|||
Visit http://xceed.com and follow @datagrid on Twitter.
|
|||
|
|||
**********************************************************************/ |
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Text; |
|||
|
|||
namespace Xceed.Wpf.Toolkit.Core |
|||
{ |
|||
public class QueryValueFromTextEventArgs : EventArgs |
|||
{ |
|||
public QueryValueFromTextEventArgs( string text, object value ) |
|||
{ |
|||
m_text = text; |
|||
m_value = value; |
|||
} |
|||
|
|||
#region Text Property
|
|||
|
|||
private string m_text; |
|||
|
|||
public string Text |
|||
{ |
|||
get { return m_text; } |
|||
} |
|||
|
|||
#endregion Text Property
|
|||
|
|||
#region Value Property
|
|||
|
|||
private object m_value; |
|||
|
|||
public object Value |
|||
{ |
|||
get { return m_value; } |
|||
set { m_value = value; } |
|||
} |
|||
|
|||
#endregion Value Property
|
|||
|
|||
#region HasParsingError Property
|
|||
|
|||
private bool m_hasParsingError; |
|||
|
|||
public bool HasParsingError |
|||
{ |
|||
get { return m_hasParsingError; } |
|||
set { m_hasParsingError = value; } |
|||
} |
|||
|
|||
#endregion HasParsingError Property
|
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,163 @@ |
|||
/************************************************************************ |
|||
|
|||
Extended WPF Toolkit |
|||
|
|||
Copyright (C) 2010-2012 Xceed Software Inc. |
|||
|
|||
This program is provided to you under the terms of the Microsoft Public |
|||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
|||
|
|||
This program can be provided to you by Xceed Software Inc. under a |
|||
proprietary commercial license agreement for use in non-Open Source |
|||
projects. The commercial version of Extended WPF Toolkit also includes |
|||
priority technical support, commercial updates, and many additional |
|||
useful WPF controls if you license Xceed Business Suite for WPF. |
|||
|
|||
Visit http://xceed.com and follow @datagrid on Twitter.
|
|||
|
|||
**********************************************************************/ |
|||
|
|||
using System; |
|||
using System.ComponentModel; |
|||
using System.Diagnostics; |
|||
using System.Linq.Expressions; |
|||
|
|||
namespace Xceed.Wpf.Toolkit.Core.Utilities |
|||
{ |
|||
[DebuggerStepThrough] |
|||
internal sealed class NotifyPropertyChangedHelper |
|||
{ |
|||
#region Constructor
|
|||
|
|||
internal NotifyPropertyChangedHelper( |
|||
INotifyPropertyChanged owner, |
|||
Action<string> notifyPropertyChangedDelegate ) |
|||
{ |
|||
if( owner == null ) |
|||
throw new ArgumentNullException( "owner" ); |
|||
|
|||
if( notifyPropertyChangedDelegate == null ) |
|||
throw new ArgumentNullException( "notifyPropertyChangedDelegate" ); |
|||
|
|||
m_owner = owner; |
|||
m_delegate = notifyPropertyChangedDelegate; |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
internal static bool PropertyChanged( string propertyName, PropertyChangedEventArgs e, bool targetPropertyOnly ) |
|||
{ |
|||
string target = e.PropertyName; |
|||
if( target == propertyName ) |
|||
return true; |
|||
|
|||
return ( !targetPropertyOnly ) |
|||
&& ( string.IsNullOrEmpty( target ) ); |
|||
} |
|||
|
|||
internal static bool PropertyChanged<TOwner, TMember>( |
|||
Expression<Func<TMember>> expression, |
|||
PropertyChangedEventArgs e, |
|||
bool targetPropertyOnly ) |
|||
{ |
|||
var body = expression.Body as MemberExpression; |
|||
if( body == null ) |
|||
throw new ArgumentException( "The expression must target a property or field.", "expression" ); |
|||
|
|||
return NotifyPropertyChangedHelper.PropertyChanged( body, typeof( TOwner ), e, targetPropertyOnly ); |
|||
} |
|||
|
|||
internal static bool PropertyChanged<TOwner, TMember>( |
|||
Expression<Func<TOwner, TMember>> expression, |
|||
PropertyChangedEventArgs e, |
|||
bool targetPropertyOnly ) |
|||
{ |
|||
var body = expression.Body as MemberExpression; |
|||
if( body == null ) |
|||
throw new ArgumentException( "The expression must target a property or field.", "expression" ); |
|||
|
|||
return NotifyPropertyChangedHelper.PropertyChanged( body, typeof( TOwner ), e, targetPropertyOnly ); |
|||
} |
|||
|
|||
internal void RaisePropertyChanged( string propertyName ) |
|||
{ |
|||
ReflectionHelper.ValidatePropertyName( m_owner, propertyName ); |
|||
|
|||
this.InvokeDelegate( propertyName ); |
|||
} |
|||
|
|||
internal void RaisePropertyChanged<TMember>( Expression<Func<TMember>> expression ) |
|||
{ |
|||
if( expression == null ) |
|||
throw new ArgumentNullException( "expression" ); |
|||
|
|||
var body = expression.Body as MemberExpression; |
|||
if( body == null ) |
|||
throw new ArgumentException( "The expression must target a property or field.", "expression" ); |
|||
|
|||
var propertyName = NotifyPropertyChangedHelper.GetPropertyName( body, m_owner.GetType() ); |
|||
|
|||
this.InvokeDelegate( propertyName ); |
|||
} |
|||
|
|||
internal void HandleReferenceChanged<TMember>( Expression<Func<TMember>> expression, ref TMember localReference, TMember newValue ) where TMember : class |
|||
{ |
|||
if( localReference != newValue ) |
|||
{ |
|||
this.ExecutePropertyChanged( expression, ref localReference, newValue ); |
|||
} |
|||
} |
|||
|
|||
internal void HandleEqualityChanged<TMember>( Expression<Func<TMember>> expression, ref TMember localReference, TMember newValue ) |
|||
{ |
|||
if( !object.Equals( localReference, newValue ) ) |
|||
{ |
|||
this.ExecutePropertyChanged( expression, ref localReference, newValue ); |
|||
} |
|||
} |
|||
|
|||
private void ExecutePropertyChanged<TMember>( Expression<Func<TMember>> expression, ref TMember localReference, TMember newValue ) |
|||
{ |
|||
TMember oldValue = localReference; |
|||
localReference = newValue; |
|||
this.RaisePropertyChanged( expression ); |
|||
} |
|||
|
|||
internal static string GetPropertyName<TMember>( Expression<Func<TMember>> expression, Type ownerType ) |
|||
{ |
|||
var body = expression.Body as MemberExpression; |
|||
if( body == null ) |
|||
throw new ArgumentException( "The expression must target a property or field.", "expression" ); |
|||
|
|||
return NotifyPropertyChangedHelper.GetPropertyName( body, ownerType ); |
|||
} |
|||
|
|||
private static bool PropertyChanged( MemberExpression expression, Type ownerType, PropertyChangedEventArgs e, bool targetPropertyOnly ) |
|||
{ |
|||
var propertyName = NotifyPropertyChangedHelper.GetPropertyName( expression, ownerType ); |
|||
|
|||
return NotifyPropertyChangedHelper.PropertyChanged( propertyName, e, targetPropertyOnly ); |
|||
} |
|||
|
|||
private static string GetPropertyName( MemberExpression expression, Type ownerType ) |
|||
{ |
|||
var targetType = expression.Expression.Type; |
|||
if( !targetType.IsAssignableFrom( ownerType ) ) |
|||
throw new ArgumentException( "The expression must target a property or field on the appropriate owner.", "expression" ); |
|||
|
|||
return ReflectionHelper.GetPropertyOrFieldName( expression ); |
|||
} |
|||
|
|||
private void InvokeDelegate( string propertyName ) |
|||
{ |
|||
m_delegate.Invoke( propertyName ); |
|||
} |
|||
|
|||
#region Private Fields
|
|||
|
|||
private readonly INotifyPropertyChanged m_owner; |
|||
private readonly Action<string> m_delegate; |
|||
|
|||
#endregion
|
|||
} |
|||
} |
|||
@ -0,0 +1,136 @@ |
|||
/************************************************************************ |
|||
|
|||
Extended WPF Toolkit |
|||
|
|||
Copyright (C) 2010-2012 Xceed Software Inc. |
|||
|
|||
This program is provided to you under the terms of the Microsoft Public |
|||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
|||
|
|||
This program can be provided to you by Xceed Software Inc. under a |
|||
proprietary commercial license agreement for use in non-Open Source |
|||
projects. The commercial version of Extended WPF Toolkit also includes |
|||
priority technical support, commercial updates, and many additional |
|||
useful WPF controls if you license Xceed Business Suite for WPF. |
|||
|
|||
Visit http://xceed.com and follow @datagrid on Twitter.
|
|||
|
|||
**********************************************************************/ |
|||
|
|||
using System; |
|||
using System.ComponentModel; |
|||
using System.Diagnostics; |
|||
using System.Linq.Expressions; |
|||
using System.Reflection; |
|||
|
|||
namespace Xceed.Wpf.Toolkit.Core.Utilities |
|||
{ |
|||
internal static class ReflectionHelper |
|||
{ |
|||
/// <summary>
|
|||
/// Check the existence of the specified public instance (i.e. non static) property against
|
|||
/// the type of the specified source object. If the property is not defined by the type,
|
|||
/// a debug assertion will fail. Typically used to validate the parameter of a
|
|||
/// RaisePropertyChanged method.
|
|||
/// </summary>
|
|||
/// <param name="sourceObject">The object for which the type will be checked.</param>
|
|||
/// <param name="propertyName">The name of the property.</param>
|
|||
[System.Diagnostics.Conditional( "DEBUG" )] |
|||
internal static void ValidatePublicPropertyName( object sourceObject, string propertyName ) |
|||
{ |
|||
if( sourceObject == null ) |
|||
throw new ArgumentNullException( "sourceObject" ); |
|||
|
|||
if( propertyName == null ) |
|||
throw new ArgumentNullException( "propertyName" ); |
|||
|
|||
System.Diagnostics.Debug.Assert( sourceObject.GetType().GetProperty( propertyName, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.FlattenHierarchy | System.Reflection.BindingFlags.Public ) != null, |
|||
string.Format( "Public property {0} not found on object of type {1}.", propertyName, sourceObject.GetType().FullName ) ); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Check the existence of the specified instance (i.e. non static) property against
|
|||
/// the type of the specified source object. If the property is not defined by the type,
|
|||
/// a debug assertion will fail. Typically used to validate the parameter of a
|
|||
/// RaisePropertyChanged method.
|
|||
/// </summary>
|
|||
/// <param name="sourceObject">The object for which the type will be checked.</param>
|
|||
/// <param name="propertyName">The name of the property.</param>
|
|||
[System.Diagnostics.Conditional( "DEBUG" )] |
|||
internal static void ValidatePropertyName( object sourceObject, string propertyName ) |
|||
{ |
|||
if( sourceObject == null ) |
|||
throw new ArgumentNullException( "sourceObject" ); |
|||
|
|||
if( propertyName == null ) |
|||
throw new ArgumentNullException( "propertyName" ); |
|||
|
|||
System.Diagnostics.Debug.Assert( sourceObject.GetType().GetProperty( propertyName, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.FlattenHierarchy | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic ) != null, |
|||
string.Format( "Public property {0} not found on object of type {1}.", propertyName, sourceObject.GetType().FullName ) ); |
|||
} |
|||
|
|||
internal static bool TryGetEnumDescriptionAttributeValue( Enum enumeration, out string description ) |
|||
{ |
|||
try |
|||
{ |
|||
FieldInfo fieldInfo = enumeration.GetType().GetField( enumeration.ToString() ); |
|||
DescriptionAttribute[] attributes = fieldInfo.GetCustomAttributes( typeof( DescriptionAttribute ), true ) as DescriptionAttribute[]; |
|||
if( ( attributes != null ) && ( attributes.Length > 0 ) ) |
|||
{ |
|||
description = attributes[ 0 ].Description; |
|||
return true; |
|||
} |
|||
} |
|||
catch |
|||
{ |
|||
} |
|||
|
|||
description = String.Empty; |
|||
return false; |
|||
} |
|||
|
|||
[DebuggerStepThrough] |
|||
internal static string GetPropertyOrFieldName( MemberExpression expression ) |
|||
{ |
|||
string propertyOrFieldName; |
|||
if( !ReflectionHelper.TryGetPropertyOrFieldName( expression, out propertyOrFieldName ) ) |
|||
throw new InvalidOperationException( "Unable to retrieve the property or field name." ); |
|||
|
|||
return propertyOrFieldName; |
|||
} |
|||
|
|||
[DebuggerStepThrough] |
|||
internal static string GetPropertyOrFieldName<TMember>( Expression<Func<TMember>> expression ) |
|||
{ |
|||
string propertyOrFieldName; |
|||
if( !ReflectionHelper.TryGetPropertyOrFieldName( expression, out propertyOrFieldName ) ) |
|||
throw new InvalidOperationException( "Unable to retrieve the property or field name." ); |
|||
|
|||
return propertyOrFieldName; |
|||
} |
|||
|
|||
[DebuggerStepThrough] |
|||
internal static bool TryGetPropertyOrFieldName( MemberExpression expression, out string propertyOrFieldName ) |
|||
{ |
|||
propertyOrFieldName = null; |
|||
|
|||
if( expression == null ) |
|||
return false; |
|||
|
|||
propertyOrFieldName = expression.Member.Name; |
|||
|
|||
return true; |
|||
} |
|||
|
|||
[DebuggerStepThrough] |
|||
internal static bool TryGetPropertyOrFieldName<TMember>( Expression<Func<TMember>> expression, out string propertyOrFieldName ) |
|||
{ |
|||
propertyOrFieldName = null; |
|||
|
|||
if( expression == null ) |
|||
return false; |
|||
|
|||
return ReflectionHelper.TryGetPropertyOrFieldName( expression.Body as MemberExpression, out propertyOrFieldName ); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,238 @@ |
|||
/************************************************************************ |
|||
|
|||
Extended WPF Toolkit |
|||
|
|||
Copyright (C) 2010-2012 Xceed Software Inc. |
|||
|
|||
This program is provided to you under the terms of the Microsoft Public |
|||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
|||
|
|||
This program can be provided to you by Xceed Software Inc. under a |
|||
proprietary commercial license agreement for use in non-Open Source |
|||
projects. The commercial version of Extended WPF Toolkit also includes |
|||
priority technical support, commercial updates, and many additional |
|||
useful WPF controls if you license Xceed Business Suite for WPF. |
|||
|
|||
Visit http://xceed.com and follow @datagrid on Twitter.
|
|||
|
|||
**********************************************************************/ |
|||
|
|||
using System; |
|||
using System.Windows; |
|||
using System.Windows.Media; |
|||
using System.Windows.Controls.Primitives; |
|||
|
|||
namespace Xceed.Wpf.Toolkit.Core.Utilities |
|||
{ |
|||
internal static class TreeHelper |
|||
{ |
|||
/// <summary>
|
|||
/// Tries its best to return the specified element's parent. It will
|
|||
/// try to find, in this order, the VisualParent, LogicalParent, LogicalTemplatedParent.
|
|||
/// It only works for Visual, FrameworkElement or FrameworkContentElement.
|
|||
/// </summary>
|
|||
/// <param name="element">The element to which to return the parent. It will only
|
|||
/// work if element is a Visual, a FrameworkElement or a FrameworkContentElement.</param>
|
|||
/// <remarks>If the logical parent is not found (Parent), we check the TemplatedParent
|
|||
/// (see FrameworkElement.Parent documentation). But, we never actually witnessed
|
|||
/// this situation.</remarks>
|
|||
public static DependencyObject GetParent( DependencyObject element ) |
|||
{ |
|||
return TreeHelper.GetParent( element, true ); |
|||
} |
|||
|
|||
private static DependencyObject GetParent( DependencyObject element, bool recurseIntoPopup ) |
|||
{ |
|||
if( recurseIntoPopup ) |
|||
{ |
|||
// Case 126732 : To correctly detect parent of a popup we must do that exception case
|
|||
Popup popup = element as Popup; |
|||
|
|||
if( ( popup != null ) && ( popup.PlacementTarget != null ) ) |
|||
return popup.PlacementTarget; |
|||
} |
|||
|
|||
Visual visual = element as Visual; |
|||
DependencyObject parent = ( visual == null ) ? null : VisualTreeHelper.GetParent( visual ); |
|||
|
|||
if( parent == null ) |
|||
{ |
|||
// No Visual parent. Check in the logical tree.
|
|||
FrameworkElement fe = element as FrameworkElement; |
|||
|
|||
if( fe != null ) |
|||
{ |
|||
parent = fe.Parent; |
|||
|
|||
if( parent == null ) |
|||
{ |
|||
parent = fe.TemplatedParent; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
FrameworkContentElement fce = element as FrameworkContentElement; |
|||
|
|||
if( fce != null ) |
|||
{ |
|||
parent = fce.Parent; |
|||
|
|||
if( parent == null ) |
|||
{ |
|||
parent = fce.TemplatedParent; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
return parent; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// This will search for a parent of the specified type.
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The type of the element to find</typeparam>
|
|||
/// <param name="startingObject">The node where the search begins. This element is not checked.</param>
|
|||
/// <returns>Returns the found element. Null if nothing is found.</returns>
|
|||
public static T FindParent<T>( DependencyObject startingObject ) where T : DependencyObject |
|||
{ |
|||
return TreeHelper.FindParent<T>( startingObject, false, null ); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// This will search for a parent of the specified type.
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The type of the element to find</typeparam>
|
|||
/// <param name="startingObject">The node where the search begins.</param>
|
|||
/// <param name="checkStartingObject">Should the specified startingObject be checked first.</param>
|
|||
/// <returns>Returns the found element. Null if nothing is found.</returns>
|
|||
public static T FindParent<T>( DependencyObject startingObject, bool checkStartingObject ) where T : DependencyObject |
|||
{ |
|||
return TreeHelper.FindParent<T>( startingObject, checkStartingObject, null ); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// This will search for a parent of the specified type.
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The type of the element to find</typeparam>
|
|||
/// <param name="startingObject">The node where the search begins.</param>
|
|||
/// <param name="checkStartingObject">Should the specified startingObject be checked first.</param>
|
|||
/// <param name="additionalCheck">Provide a callback to check additional properties
|
|||
/// of the found elements. Can be left Null if no additional criteria are needed.</param>
|
|||
/// <returns>Returns the found element. Null if nothing is found.</returns>
|
|||
/// <example>Button button = TreeHelper.FindParent<Button>( this, foundChild => foundChild.Focusable );</example>
|
|||
public static T FindParent<T>( DependencyObject startingObject, bool checkStartingObject, Func<T, bool> additionalCheck ) where T : DependencyObject |
|||
{ |
|||
T foundElement; |
|||
DependencyObject parent = ( checkStartingObject ? startingObject : TreeHelper.GetParent( startingObject, true ) ); |
|||
|
|||
while( parent != null ) |
|||
{ |
|||
foundElement = parent as T; |
|||
|
|||
if( foundElement != null ) |
|||
{ |
|||
if( additionalCheck == null ) |
|||
{ |
|||
return foundElement; |
|||
} |
|||
else |
|||
{ |
|||
if( additionalCheck( foundElement ) ) |
|||
return foundElement; |
|||
} |
|||
} |
|||
|
|||
parent = TreeHelper.GetParent( parent, true ); |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// This will search for a child of the specified type. The search is performed
|
|||
/// hierarchically, breadth first (as opposed to depth first).
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The type of the element to find</typeparam>
|
|||
/// <param name="parent">The root of the tree to search for. This element itself is not checked.</param>
|
|||
/// <returns>Returns the found element. Null if nothing is found.</returns>
|
|||
public static T FindChild<T>( DependencyObject parent ) where T : DependencyObject |
|||
{ |
|||
return TreeHelper.FindChild<T>( parent, null ); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// This will search for a child of the specified type. The search is performed
|
|||
/// hierarchically, breadth first (as opposed to depth first).
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The type of the element to find</typeparam>
|
|||
/// <param name="parent">The root of the tree to search for. This element itself is not checked.</param>
|
|||
/// <param name="additionalCheck">Provide a callback to check additional properties
|
|||
/// of the found elements. Can be left Null if no additional criteria are needed.</param>
|
|||
/// <returns>Returns the found element. Null if nothing is found.</returns>
|
|||
/// <example>Button button = TreeHelper.FindChild<Button>( this, foundChild => foundChild.Focusable );</example>
|
|||
public static T FindChild<T>( DependencyObject parent, Func<T, bool> additionalCheck ) where T : DependencyObject |
|||
{ |
|||
int childrenCount = VisualTreeHelper.GetChildrenCount( parent ); |
|||
T child; |
|||
|
|||
for( int index = 0; index < childrenCount; index++ ) |
|||
{ |
|||
child = VisualTreeHelper.GetChild( parent, index ) as T; |
|||
|
|||
if( child != null ) |
|||
{ |
|||
if( additionalCheck == null ) |
|||
{ |
|||
return child; |
|||
} |
|||
else |
|||
{ |
|||
if( additionalCheck( child ) ) |
|||
return child; |
|||
} |
|||
} |
|||
} |
|||
|
|||
for( int index = 0; index < childrenCount; index++ ) |
|||
{ |
|||
child = TreeHelper.FindChild<T>( VisualTreeHelper.GetChild( parent, index ), additionalCheck ); |
|||
|
|||
if( child != null ) |
|||
return child; |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns true if the specified element is a child of parent somewhere in the visual
|
|||
/// tree. This method will work for Visual, FrameworkElement and FrameworkContentElement.
|
|||
/// </summary>
|
|||
/// <param name="element">The element that is potentially a child of the specified parent.</param>
|
|||
/// <param name="parent">The element that is potentially a parent of the specified element.</param>
|
|||
public static bool IsDescendantOf( DependencyObject element, DependencyObject parent ) |
|||
{ |
|||
return TreeHelper.IsDescendantOf( element, parent, true ); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns true if the specified element is a child of parent somewhere in the visual
|
|||
/// tree. This method will work for Visual, FrameworkElement and FrameworkContentElement.
|
|||
/// </summary>
|
|||
/// <param name="element">The element that is potentially a child of the specified parent.</param>
|
|||
/// <param name="parent">The element that is potentially a parent of the specified element.</param>
|
|||
public static bool IsDescendantOf( DependencyObject element, DependencyObject parent, bool recurseIntoPopup ) |
|||
{ |
|||
while( element != null ) |
|||
{ |
|||
if( element == parent ) |
|||
return true; |
|||
|
|||
element = TreeHelper.GetParent( element, recurseIntoPopup ); |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,153 @@ |
|||
/************************************************************************ |
|||
|
|||
Extended WPF Toolkit |
|||
|
|||
Copyright (C) 2010-2012 Xceed Software Inc. |
|||
|
|||
This program is provided to you under the terms of the Microsoft Public |
|||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
|||
|
|||
This program can be provided to you by Xceed Software Inc. under a |
|||
proprietary commercial license agreement for use in non-Open Source |
|||
projects. The commercial version of Extended WPF Toolkit also includes |
|||
priority technical support, commercial updates, and many additional |
|||
useful WPF controls if you license Xceed Business Suite for WPF. |
|||
|
|||
Visit http://xceed.com and follow @datagrid on Twitter.
|
|||
|
|||
**********************************************************************/ |
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Windows; |
|||
using System.Collections; |
|||
using System.Windows.Data; |
|||
|
|||
namespace Xceed.Wpf.Toolkit.Core.Utilities |
|||
{ |
|||
/// <summary>
|
|||
/// This helper class will raise events when a specific
|
|||
/// path value on one or many items changes.
|
|||
/// </summary>
|
|||
internal class ValueChangeHelper : DependencyObject |
|||
{ |
|||
|
|||
#region Value Property
|
|||
/// <summary>
|
|||
/// This private property serves as the target of a binding that monitors the value of the binding
|
|||
/// of each item in the source.
|
|||
/// </summary>
|
|||
private static readonly DependencyProperty ValueProperty = DependencyProperty.Register( "Value", typeof( object ), typeof( ValueChangeHelper ), new UIPropertyMetadata( null, OnValueChanged ) ); |
|||
private object Value |
|||
{ |
|||
get |
|||
{ |
|||
return ( object )GetValue( ValueProperty ); |
|||
} |
|||
set |
|||
{ |
|||
SetValue( ValueProperty, value ); |
|||
} |
|||
} |
|||
|
|||
private static void OnValueChanged( DependencyObject sender, DependencyPropertyChangedEventArgs args ) |
|||
{ |
|||
( ( ValueChangeHelper )sender ).RaiseValueChanged(); |
|||
} |
|||
#endregion
|
|||
|
|||
public event EventHandler ValueChanged; |
|||
|
|||
#region Constructor
|
|||
|
|||
public ValueChangeHelper(Action changeCallback) |
|||
{ |
|||
if( changeCallback == null ) |
|||
throw new ArgumentNullException( "changeCallback" ); |
|||
|
|||
this.ValueChanged += ( s, args ) => changeCallback(); |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region Methods
|
|||
|
|||
public void UpdateValueSource( object sourceItem, string path ) |
|||
{ |
|||
BindingBase binding = null; |
|||
if( sourceItem != null && path != null ) |
|||
{ |
|||
binding = new Binding( path ) { Source = sourceItem }; |
|||
} |
|||
|
|||
this.UpdateBinding( binding ); |
|||
} |
|||
|
|||
public void UpdateValueSource( IEnumerable sourceItems, string path ) |
|||
{ |
|||
BindingBase binding = null; |
|||
if( sourceItems != null && path != null ) |
|||
{ |
|||
MultiBinding multiBinding = new MultiBinding(); |
|||
multiBinding.Converter = new BlankMultiValueConverter(); |
|||
|
|||
foreach( var item in sourceItems ) |
|||
{ |
|||
multiBinding.Bindings.Add( new Binding( path ) { Source = item } ); |
|||
} |
|||
|
|||
binding = multiBinding; |
|||
} |
|||
|
|||
this.UpdateBinding( binding ); |
|||
} |
|||
|
|||
private void UpdateBinding( BindingBase binding ) |
|||
{ |
|||
if( binding != null ) |
|||
{ |
|||
BindingOperations.SetBinding( this, ValueChangeHelper.ValueProperty, binding ); |
|||
} |
|||
else |
|||
{ |
|||
this.ClearBinding(); |
|||
} |
|||
} |
|||
|
|||
private void ClearBinding() |
|||
{ |
|||
BindingOperations.ClearBinding( this, ValueChangeHelper.ValueProperty ); |
|||
} |
|||
|
|||
private void RaiseValueChanged() |
|||
{ |
|||
if( this.ValueChanged != null ) |
|||
{ |
|||
this.ValueChanged( this, EventArgs.Empty ); |
|||
} |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region BlankMultiValueConverter private class
|
|||
|
|||
private class BlankMultiValueConverter : IMultiValueConverter |
|||
{ |
|||
public object Convert( object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture ) |
|||
{ |
|||
// We will not use the result anyway. We just want the change notification to kick in.
|
|||
// Return a new object to have a different value.
|
|||
return new object(); |
|||
} |
|||
|
|||
public object[] ConvertBack( object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture ) |
|||
{ |
|||
throw new InvalidOperationException(); |
|||
} |
|||
} |
|||
|
|||
#endregion
|
|||
} |
|||
} |
|||
@ -0,0 +1,108 @@ |
|||
/************************************************************************ |
|||
|
|||
Extended WPF Toolkit |
|||
|
|||
Copyright (C) 2010-2012 Xceed Software Inc. |
|||
|
|||
This program is provided to you under the terms of the Microsoft Public |
|||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
|||
|
|||
This program can be provided to you by Xceed Software Inc. under a |
|||
proprietary commercial license agreement for use in non-Open Source |
|||
projects. The commercial version of Extended WPF Toolkit also includes |
|||
priority technical support, commercial updates, and many additional |
|||
useful WPF controls if you license Xceed Business Suite for WPF. |
|||
|
|||
Visit http://xceed.com and follow @datagrid on Twitter.
|
|||
|
|||
**********************************************************************/ |
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Text; |
|||
using System.ComponentModel; |
|||
|
|||
namespace Xceed.Wpf.Toolkit |
|||
{ |
|||
public class AutoCompletingMaskEventArgs : CancelEventArgs |
|||
{ |
|||
public AutoCompletingMaskEventArgs( MaskedTextProvider maskedTextProvider, int startPosition, int selectionLength, string input ) |
|||
{ |
|||
m_autoCompleteStartPosition = -1; |
|||
|
|||
m_maskedTextProvider = maskedTextProvider; |
|||
m_startPosition = startPosition; |
|||
m_selectionLength = selectionLength; |
|||
m_input = input; |
|||
} |
|||
|
|||
#region MaskedTextProvider PROPERTY
|
|||
|
|||
private MaskedTextProvider m_maskedTextProvider; |
|||
|
|||
public MaskedTextProvider MaskedTextProvider |
|||
{ |
|||
get { return m_maskedTextProvider; } |
|||
} |
|||
|
|||
#endregion MaskedTextProvider PROPERTY
|
|||
|
|||
#region StartPosition PROPERTY
|
|||
|
|||
private int m_startPosition; |
|||
|
|||
public int StartPosition |
|||
{ |
|||
get { return m_startPosition; } |
|||
} |
|||
|
|||
#endregion StartPosition PROPERTY
|
|||
|
|||
#region SelectionLength PROPERTY
|
|||
|
|||
private int m_selectionLength; |
|||
|
|||
public int SelectionLength |
|||
{ |
|||
get { return m_selectionLength; } |
|||
} |
|||
|
|||
#endregion SelectionLength PROPERTY
|
|||
|
|||
#region Input PROPERTY
|
|||
|
|||
private string m_input; |
|||
|
|||
public string Input |
|||
{ |
|||
get { return m_input; } |
|||
} |
|||
|
|||
#endregion Input PROPERTY
|
|||
|
|||
|
|||
#region AutoCompleteStartPosition PROPERTY
|
|||
|
|||
private int m_autoCompleteStartPosition; |
|||
|
|||
public int AutoCompleteStartPosition |
|||
{ |
|||
get { return m_autoCompleteStartPosition; } |
|||
set { m_autoCompleteStartPosition = value; } |
|||
} |
|||
|
|||
#endregion AutoCompleteStartPosition PROPERTY
|
|||
|
|||
#region AutoCompleteText PROPERTY
|
|||
|
|||
private string m_autoCompleteText; |
|||
|
|||
public string AutoCompleteText |
|||
{ |
|||
get { return m_autoCompleteText; } |
|||
set { m_autoCompleteText = value; } |
|||
} |
|||
|
|||
#endregion AutoCompleteText PROPERTY
|
|||
} |
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
/************************************************************************ |
|||
|
|||
Extended WPF Toolkit |
|||
|
|||
Copyright (C) 2010-2012 Xceed Software Inc. |
|||
|
|||
This program is provided to you under the terms of the Microsoft Public |
|||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
|||
|
|||
This program can be provided to you by Xceed Software Inc. under a |
|||
proprietary commercial license agreement for use in non-Open Source |
|||
projects. The commercial version of Extended WPF Toolkit also includes |
|||
priority technical support, commercial updates, and many additional |
|||
useful WPF controls if you license Xceed Business Suite for WPF. |
|||
|
|||
Visit http://xceed.com and follow @datagrid on Twitter.
|
|||
|
|||
**********************************************************************/ |
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Text; |
|||
|
|||
namespace Xceed.Wpf.Toolkit |
|||
{ |
|||
public enum InsertKeyMode |
|||
{ |
|||
Default = 0, |
|||
Insert = 1, |
|||
Overwrite = 2 |
|||
} |
|||
} |
|||
@ -0,0 +1,33 @@ |
|||
/************************************************************************ |
|||
|
|||
Extended WPF Toolkit |
|||
|
|||
Copyright (C) 2010-2012 Xceed Software Inc. |
|||
|
|||
This program is provided to you under the terms of the Microsoft Public |
|||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
|||
|
|||
This program can be provided to you by Xceed Software Inc. under a |
|||
proprietary commercial license agreement for use in non-Open Source |
|||
projects. The commercial version of Extended WPF Toolkit also includes |
|||
priority technical support, commercial updates, and many additional |
|||
useful WPF controls if you license Xceed Business Suite for WPF. |
|||
|
|||
Visit http://xceed.com and follow @datagrid on Twitter.
|
|||
|
|||
**********************************************************************/ |
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Text; |
|||
|
|||
namespace Xceed.Wpf.Toolkit |
|||
{ |
|||
public enum MaskFormat |
|||
{ |
|||
ExcludePromptAndLiterals, |
|||
IncludeLiterals, |
|||
IncludePrompt, |
|||
IncludePromptAndLiterals |
|||
} |
|||
} |
|||
File diff suppressed because it is too large
@ -0,0 +1,55 @@ |
|||
/************************************************************************ |
|||
|
|||
Extended WPF Toolkit |
|||
|
|||
Copyright (C) 2010-2012 Xceed Software Inc. |
|||
|
|||
This program is provided to you under the terms of the Microsoft Public |
|||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
|||
|
|||
This program can be provided to you by Xceed Software Inc. under a |
|||
proprietary commercial license agreement for use in non-Open Source |
|||
projects. The commercial version of Extended WPF Toolkit also includes |
|||
priority technical support, commercial updates, and many additional |
|||
useful WPF controls if you license Xceed Business Suite for WPF. |
|||
|
|||
Visit http://xceed.com and follow @datagrid on Twitter.
|
|||
|
|||
**********************************************************************/ |
|||
|
|||
using System; |
|||
using System.Windows; |
|||
|
|||
namespace Xceed.Wpf.Toolkit |
|||
{ |
|||
public class ByteUpDown : CommonNumericUpDown<byte> |
|||
{ |
|||
#region Constructors
|
|||
|
|||
static ByteUpDown() |
|||
{ |
|||
UpdateMetadata( typeof( ByteUpDown ), default( byte ), ( byte )1, byte.MinValue, byte.MaxValue ); |
|||
} |
|||
|
|||
public ByteUpDown() |
|||
: base( Byte.Parse, Decimal.ToByte ) |
|||
{ |
|||
} |
|||
|
|||
#endregion //Constructors
|
|||
|
|||
#region Base Class Overrides
|
|||
|
|||
protected override byte IncrementValue( byte value, byte increment ) |
|||
{ |
|||
return ( byte )( value + increment ); |
|||
} |
|||
|
|||
protected override byte DecrementValue( byte value, byte increment ) |
|||
{ |
|||
return ( byte )( value - increment ); |
|||
} |
|||
|
|||
#endregion //Base Class Overrides
|
|||
} |
|||
} |
|||
@ -0,0 +1,184 @@ |
|||
/************************************************************************ |
|||
|
|||
Extended WPF Toolkit |
|||
|
|||
Copyright (C) 2010-2012 Xceed Software Inc. |
|||
|
|||
This program is provided to you under the terms of the Microsoft Public |
|||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
|||
|
|||
This program can be provided to you by Xceed Software Inc. under a |
|||
proprietary commercial license agreement for use in non-Open Source |
|||
projects. The commercial version of Extended WPF Toolkit also includes |
|||
priority technical support, commercial updates, and many additional |
|||
useful WPF controls if you license Xceed Business Suite for WPF. |
|||
|
|||
Visit http://xceed.com and follow @datagrid on Twitter.
|
|||
|
|||
**********************************************************************/ |
|||
|
|||
using System; |
|||
using System.Windows; |
|||
using System.Globalization; |
|||
|
|||
namespace Xceed.Wpf.Toolkit |
|||
{ |
|||
public abstract class CommonNumericUpDown<T> : NumericUpDown<T?> where T : struct, IFormattable, IComparable<T> |
|||
{ |
|||
protected delegate T FromText( string s, NumberStyles style, IFormatProvider provider ); |
|||
protected delegate T FromDecimal( decimal d ); |
|||
|
|||
private FromText _fromText; |
|||
private FromDecimal _fromDecimal; |
|||
|
|||
protected CommonNumericUpDown( FromText fromText, FromDecimal fromDecimal ) |
|||
{ |
|||
if( fromText == null ) |
|||
throw new ArgumentNullException( "parseMethod" ); |
|||
|
|||
if( fromDecimal == null ) |
|||
throw new ArgumentNullException( "fromDecimal" ); |
|||
|
|||
_fromText = fromText; |
|||
_fromDecimal = fromDecimal; |
|||
} |
|||
|
|||
protected static void UpdateMetadata( Type type, T? defaultValue, T? increment, T? minValue, T? maxValue ) |
|||
{ |
|||
DefaultStyleKeyProperty.OverrideMetadata( type, new FrameworkPropertyMetadata( type ) ); |
|||
DefaultValueProperty.OverrideMetadata( type, new FrameworkPropertyMetadata( defaultValue ) ); |
|||
IncrementProperty.OverrideMetadata( type, new FrameworkPropertyMetadata( increment ) ); |
|||
MaximumProperty.OverrideMetadata( type, new FrameworkPropertyMetadata( maxValue ) ); |
|||
MinimumProperty.OverrideMetadata( type, new FrameworkPropertyMetadata( minValue ) ); |
|||
} |
|||
|
|||
private bool IsLowerThan( T? value1, T? value2 ) |
|||
{ |
|||
if( value1 == null || value2 == null ) |
|||
return false; |
|||
|
|||
return ( value1.Value.CompareTo( value2.Value ) < 0 ); |
|||
} |
|||
|
|||
private bool IsGreaterThan( T? value1, T? value2 ) |
|||
{ |
|||
if( value1 == null || value2 == null ) |
|||
return false; |
|||
|
|||
return ( value1.Value.CompareTo( value2.Value ) > 0 ); |
|||
} |
|||
|
|||
private bool HandleNullSpin() |
|||
{ |
|||
if( !Value.HasValue ) |
|||
{ |
|||
Value = DefaultValue; |
|||
return true; |
|||
} |
|||
else if( !Increment.HasValue ) |
|||
{ |
|||
return true; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
private T? CoerceValue( T value ) |
|||
{ |
|||
if( IsLowerThan( value, Minimum ) ) |
|||
return Minimum; |
|||
else if( IsGreaterThan( value, Maximum ) ) |
|||
return Maximum; |
|||
else |
|||
return value; |
|||
} |
|||
|
|||
#region Base Class Overrides
|
|||
|
|||
|
|||
protected override object OnCoerceValue( object newValue ) |
|||
{ |
|||
ValidateMinMax( ( T? )newValue ); |
|||
|
|||
return newValue; |
|||
} |
|||
|
|||
|
|||
|
|||
protected override void OnIncrement() |
|||
{ |
|||
if( !HandleNullSpin() ) |
|||
{ |
|||
T result = IncrementValue( Value.Value, Increment.Value ); |
|||
Value = CoerceValue( result ); |
|||
} |
|||
} |
|||
|
|||
protected override void OnDecrement() |
|||
{ |
|||
if( !HandleNullSpin() ) |
|||
{ |
|||
T result = DecrementValue( Value.Value, Increment.Value ); |
|||
Value = CoerceValue( result ); |
|||
} |
|||
} |
|||
|
|||
protected override T? ConvertTextToValue( string text ) |
|||
{ |
|||
T? result = null; |
|||
|
|||
if( String.IsNullOrEmpty( text ) ) |
|||
return result; |
|||
|
|||
//don't know why someone would format a T as %, but just in case they do.
|
|||
result = FormatString.Contains( "P" ) |
|||
? _fromDecimal( ParsePercent( text, CultureInfo ) ) |
|||
: _fromText( text, NumberStyles.Any, CultureInfo ); |
|||
|
|||
ValidateMinMax( result ); |
|||
|
|||
return result; |
|||
} |
|||
|
|||
protected override string ConvertValueToText() |
|||
{ |
|||
if( Value == null ) |
|||
return string.Empty; |
|||
|
|||
return Value.Value.ToString( FormatString, CultureInfo ); |
|||
} |
|||
|
|||
protected override void SetValidSpinDirection() |
|||
{ |
|||
ValidSpinDirections validDirections = ValidSpinDirections.None; |
|||
|
|||
if( IsLowerThan( Value, Maximum ) || !Value.HasValue ) |
|||
validDirections = validDirections | ValidSpinDirections.Increase; |
|||
|
|||
if( IsGreaterThan( Value, Minimum ) || !Value.HasValue ) |
|||
validDirections = validDirections | ValidSpinDirections.Decrease; |
|||
|
|||
if( Spinner != null ) |
|||
Spinner.ValidSpinDirection = validDirections; |
|||
} |
|||
|
|||
private void ValidateMinMax( T? value ) |
|||
{ |
|||
if( IsLowerThan( value, Minimum ) ) |
|||
throw new ArgumentOutOfRangeException( "Minimum", String.Format( "Value must be greater than MinValue of {0}", Minimum ) ); |
|||
else if( IsGreaterThan( value, Maximum ) ) |
|||
throw new ArgumentOutOfRangeException( "Maximum", String.Format( "Value must be less than MaxValue of {0}", Maximum ) ); |
|||
} |
|||
|
|||
#endregion //Base Class Overrides
|
|||
|
|||
|
|||
#region Abstract Methods
|
|||
|
|||
protected abstract T IncrementValue( T value, T increment ); |
|||
|
|||
protected abstract T DecrementValue( T value, T increment ); |
|||
|
|||
#endregion
|
|||
} |
|||
} |
|||
@ -0,0 +1,55 @@ |
|||
/************************************************************************ |
|||
|
|||
Extended WPF Toolkit |
|||
|
|||
Copyright (C) 2010-2012 Xceed Software Inc. |
|||
|
|||
This program is provided to you under the terms of the Microsoft Public |
|||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
|||
|
|||
This program can be provided to you by Xceed Software Inc. under a |
|||
proprietary commercial license agreement for use in non-Open Source |
|||
projects. The commercial version of Extended WPF Toolkit also includes |
|||
priority technical support, commercial updates, and many additional |
|||
useful WPF controls if you license Xceed Business Suite for WPF. |
|||
|
|||
Visit http://xceed.com and follow @datagrid on Twitter.
|
|||
|
|||
**********************************************************************/ |
|||
|
|||
using System; |
|||
using System.Windows; |
|||
|
|||
namespace Xceed.Wpf.Toolkit |
|||
{ |
|||
public class LongUpDown : CommonNumericUpDown<long> |
|||
{ |
|||
#region Constructors
|
|||
|
|||
static LongUpDown() |
|||
{ |
|||
UpdateMetadata( typeof( LongUpDown ), default( long ), 1L, long.MinValue, long.MaxValue ); |
|||
} |
|||
|
|||
public LongUpDown() |
|||
: base( Int64.Parse, Decimal.ToInt64 ) |
|||
{ |
|||
} |
|||
|
|||
#endregion //Constructors
|
|||
|
|||
#region Base Class Overrides
|
|||
|
|||
protected override long IncrementValue( long value, long increment ) |
|||
{ |
|||
return value + increment; |
|||
} |
|||
|
|||
protected override long DecrementValue( long value, long increment ) |
|||
{ |
|||
return value - increment; |
|||
} |
|||
|
|||
#endregion //Base Class Overrides
|
|||
} |
|||
} |
|||
@ -0,0 +1,55 @@ |
|||
/************************************************************************ |
|||
|
|||
Extended WPF Toolkit |
|||
|
|||
Copyright (C) 2010-2012 Xceed Software Inc. |
|||
|
|||
This program is provided to you under the terms of the Microsoft Public |
|||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
|||
|
|||
This program can be provided to you by Xceed Software Inc. under a |
|||
proprietary commercial license agreement for use in non-Open Source |
|||
projects. The commercial version of Extended WPF Toolkit also includes |
|||
priority technical support, commercial updates, and many additional |
|||
useful WPF controls if you license Xceed Business Suite for WPF. |
|||
|
|||
Visit http://xceed.com and follow @datagrid on Twitter.
|
|||
|
|||
**********************************************************************/ |
|||
|
|||
using System; |
|||
using System.Windows; |
|||
|
|||
namespace Xceed.Wpf.Toolkit |
|||
{ |
|||
internal class SByteUpDown : CommonNumericUpDown<sbyte> |
|||
{ |
|||
#region Constructors
|
|||
|
|||
static SByteUpDown() |
|||
{ |
|||
UpdateMetadata( typeof( SByteUpDown ), default( sbyte ), ( sbyte )1, sbyte.MinValue, sbyte.MaxValue ); |
|||
} |
|||
|
|||
public SByteUpDown() |
|||
: base( sbyte.Parse, Decimal.ToSByte ) |
|||
{ |
|||
} |
|||
|
|||
#endregion //Constructors
|
|||
|
|||
#region Base Class Overrides
|
|||
|
|||
protected override sbyte IncrementValue( sbyte value, sbyte increment ) |
|||
{ |
|||
return ( sbyte )( value + increment ); |
|||
} |
|||
|
|||
protected override sbyte DecrementValue( sbyte value, sbyte increment ) |
|||
{ |
|||
return ( sbyte )( value - increment ); |
|||
} |
|||
|
|||
#endregion //Base Class Overrides
|
|||
} |
|||
} |
|||
@ -0,0 +1,55 @@ |
|||
/************************************************************************ |
|||
|
|||
Extended WPF Toolkit |
|||
|
|||
Copyright (C) 2010-2012 Xceed Software Inc. |
|||
|
|||
This program is provided to you under the terms of the Microsoft Public |
|||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
|||
|
|||
This program can be provided to you by Xceed Software Inc. under a |
|||
proprietary commercial license agreement for use in non-Open Source |
|||
projects. The commercial version of Extended WPF Toolkit also includes |
|||
priority technical support, commercial updates, and many additional |
|||
useful WPF controls if you license Xceed Business Suite for WPF. |
|||
|
|||
Visit http://xceed.com and follow @datagrid on Twitter.
|
|||
|
|||
**********************************************************************/ |
|||
|
|||
using System; |
|||
using System.Windows; |
|||
|
|||
namespace Xceed.Wpf.Toolkit |
|||
{ |
|||
public class ShortUpDown : CommonNumericUpDown<short> |
|||
{ |
|||
#region Constructors
|
|||
|
|||
static ShortUpDown() |
|||
{ |
|||
UpdateMetadata( typeof( ShortUpDown ), default( short ), ( short )1, short.MinValue, short.MaxValue ); |
|||
} |
|||
|
|||
public ShortUpDown() |
|||
: base( Int16.Parse, Decimal.ToInt16 ) |
|||
{ |
|||
} |
|||
|
|||
#endregion //Constructors
|
|||
|
|||
#region Base Class Overrides
|
|||
|
|||
protected override short IncrementValue( short value, short increment ) |
|||
{ |
|||
return ( short )( value + increment ); |
|||
} |
|||
|
|||
protected override short DecrementValue( short value, short increment ) |
|||
{ |
|||
return ( short )( value - increment ); |
|||
} |
|||
|
|||
#endregion //Base Class Overrides
|
|||
} |
|||
} |
|||
@ -0,0 +1,55 @@ |
|||
/************************************************************************ |
|||
|
|||
Extended WPF Toolkit |
|||
|
|||
Copyright (C) 2010-2012 Xceed Software Inc. |
|||
|
|||
This program is provided to you under the terms of the Microsoft Public |
|||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
|||
|
|||
This program can be provided to you by Xceed Software Inc. under a |
|||
proprietary commercial license agreement for use in non-Open Source |
|||
projects. The commercial version of Extended WPF Toolkit also includes |
|||
priority technical support, commercial updates, and many additional |
|||
useful WPF controls if you license Xceed Business Suite for WPF. |
|||
|
|||
Visit http://xceed.com and follow @datagrid on Twitter.
|
|||
|
|||
**********************************************************************/ |
|||
|
|||
using System; |
|||
using System.Windows; |
|||
|
|||
namespace Xceed.Wpf.Toolkit |
|||
{ |
|||
public class SingleUpDown : CommonNumericUpDown<float> |
|||
{ |
|||
#region Constructors
|
|||
|
|||
static SingleUpDown() |
|||
{ |
|||
UpdateMetadata( typeof( SingleUpDown ), default( float ), 1f, float.MinValue, float.MaxValue ); |
|||
} |
|||
|
|||
public SingleUpDown() |
|||
: base( Single.Parse, Decimal.ToSingle ) |
|||
{ |
|||
} |
|||
|
|||
#endregion //Constructors
|
|||
|
|||
#region Base Class Overrides
|
|||
|
|||
protected override float IncrementValue( float value, float increment ) |
|||
{ |
|||
return value + increment; |
|||
} |
|||
|
|||
protected override float DecrementValue( float value, float increment ) |
|||
{ |
|||
return value - increment; |
|||
} |
|||
|
|||
#endregion //Base Class Overrides
|
|||
} |
|||
} |
|||
@ -0,0 +1,55 @@ |
|||
/************************************************************************ |
|||
|
|||
Extended WPF Toolkit |
|||
|
|||
Copyright (C) 2010-2012 Xceed Software Inc. |
|||
|
|||
This program is provided to you under the terms of the Microsoft Public |
|||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
|||
|
|||
This program can be provided to you by Xceed Software Inc. under a |
|||
proprietary commercial license agreement for use in non-Open Source |
|||
projects. The commercial version of Extended WPF Toolkit also includes |
|||
priority technical support, commercial updates, and many additional |
|||
useful WPF controls if you license Xceed Business Suite for WPF. |
|||
|
|||
Visit http://xceed.com and follow @datagrid on Twitter.
|
|||
|
|||
**********************************************************************/ |
|||
|
|||
using System; |
|||
using System.Windows; |
|||
|
|||
namespace Xceed.Wpf.Toolkit |
|||
{ |
|||
internal class UIntegerUpDown : CommonNumericUpDown<uint> |
|||
{ |
|||
#region Constructors
|
|||
|
|||
static UIntegerUpDown() |
|||
{ |
|||
UpdateMetadata( typeof( UIntegerUpDown ), default( uint ), ( uint )1, uint.MinValue, uint.MaxValue ); |
|||
} |
|||
|
|||
public UIntegerUpDown() |
|||
: base( uint.Parse, Decimal.ToUInt32 ) |
|||
{ |
|||
} |
|||
|
|||
#endregion //Constructors
|
|||
|
|||
#region Base Class Overrides
|
|||
|
|||
protected override uint IncrementValue( uint value, uint increment ) |
|||
{ |
|||
return ( uint )( value + increment ); |
|||
} |
|||
|
|||
protected override uint DecrementValue( uint value, uint increment ) |
|||
{ |
|||
return ( uint )( value - increment ); |
|||
} |
|||
|
|||
#endregion //Base Class Overrides
|
|||
} |
|||
} |
|||
@ -0,0 +1,55 @@ |
|||
/************************************************************************ |
|||
|
|||
Extended WPF Toolkit |
|||
|
|||
Copyright (C) 2010-2012 Xceed Software Inc. |
|||
|
|||
This program is provided to you under the terms of the Microsoft Public |
|||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
|||
|
|||
This program can be provided to you by Xceed Software Inc. under a |
|||
proprietary commercial license agreement for use in non-Open Source |
|||
projects. The commercial version of Extended WPF Toolkit also includes |
|||
priority technical support, commercial updates, and many additional |
|||
useful WPF controls if you license Xceed Business Suite for WPF. |
|||
|
|||
Visit http://xceed.com and follow @datagrid on Twitter.
|
|||
|
|||
**********************************************************************/ |
|||
|
|||
using System; |
|||
using System.Windows; |
|||
|
|||
namespace Xceed.Wpf.Toolkit |
|||
{ |
|||
internal class ULongUpDown : CommonNumericUpDown<ulong> |
|||
{ |
|||
#region Constructors
|
|||
|
|||
static ULongUpDown() |
|||
{ |
|||
UpdateMetadata( typeof( ULongUpDown ), default( ulong ), ( ulong )1, ulong.MinValue, ulong.MaxValue ); |
|||
} |
|||
|
|||
public ULongUpDown() |
|||
: base( ulong.Parse, Decimal.ToUInt64 ) |
|||
{ |
|||
} |
|||
|
|||
#endregion //Constructors
|
|||
|
|||
#region Base Class Overrides
|
|||
|
|||
protected override ulong IncrementValue( ulong value, ulong increment ) |
|||
{ |
|||
return ( ulong )( value + increment ); |
|||
} |
|||
|
|||
protected override ulong DecrementValue( ulong value, ulong increment ) |
|||
{ |
|||
return ( ulong )( value - increment ); |
|||
} |
|||
|
|||
#endregion //Base Class Overrides
|
|||
} |
|||
} |
|||
@ -0,0 +1,55 @@ |
|||
/************************************************************************ |
|||
|
|||
Extended WPF Toolkit |
|||
|
|||
Copyright (C) 2010-2012 Xceed Software Inc. |
|||
|
|||
This program is provided to you under the terms of the Microsoft Public |
|||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
|||
|
|||
This program can be provided to you by Xceed Software Inc. under a |
|||
proprietary commercial license agreement for use in non-Open Source |
|||
projects. The commercial version of Extended WPF Toolkit also includes |
|||
priority technical support, commercial updates, and many additional |
|||
useful WPF controls if you license Xceed Business Suite for WPF. |
|||
|
|||
Visit http://xceed.com and follow @datagrid on Twitter.
|
|||
|
|||
**********************************************************************/ |
|||
|
|||
using System; |
|||
using System.Windows; |
|||
|
|||
namespace Xceed.Wpf.Toolkit |
|||
{ |
|||
internal class UShortUpDown : CommonNumericUpDown<ushort> |
|||
{ |
|||
#region Constructors
|
|||
|
|||
static UShortUpDown() |
|||
{ |
|||
UpdateMetadata( typeof( UShortUpDown ), default( ushort ), ( ushort )1, ushort.MinValue, ushort.MaxValue ); |
|||
} |
|||
|
|||
public UShortUpDown() |
|||
: base( ushort.Parse, Decimal.ToUInt16 ) |
|||
{ |
|||
} |
|||
|
|||
#endregion //Constructors
|
|||
|
|||
#region Base Class Overrides
|
|||
|
|||
protected override ushort IncrementValue( ushort value, ushort increment ) |
|||
{ |
|||
return ( ushort )( value + increment ); |
|||
} |
|||
|
|||
protected override ushort DecrementValue( ushort value, ushort increment ) |
|||
{ |
|||
return ( ushort )( value - increment ); |
|||
} |
|||
|
|||
#endregion //Base Class Overrides
|
|||
} |
|||
} |
|||
@ -0,0 +1,726 @@ |
|||
/************************************************************************ |
|||
|
|||
Extended WPF Toolkit |
|||
|
|||
Copyright (C) 2010-2012 Xceed Software Inc. |
|||
|
|||
This program is provided to you under the terms of the Microsoft Public |
|||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
|||
|
|||
This program can be provided to you by Xceed Software Inc. under a |
|||
proprietary commercial license agreement for use in non-Open Source |
|||
projects. The commercial version of Extended WPF Toolkit also includes |
|||
priority technical support, commercial updates, and many additional |
|||
useful WPF controls if you license Xceed Business Suite for WPF. |
|||
|
|||
Visit http://xceed.com and follow @datagrid on Twitter.
|
|||
|
|||
**********************************************************************/ |
|||
|
|||
using System; |
|||
using System.ComponentModel; |
|||
using System.Windows; |
|||
using System.Windows.Controls; |
|||
using System.Windows.Input; |
|||
|
|||
namespace Xceed.Wpf.Toolkit.Obselete |
|||
{ |
|||
[Obsolete("Legacy implementation of MaskedTextBox. Use Xceed.Wpf.Toolkit.MaskedTextBox instead", false)] |
|||
public class MaskedTextBox : TextBox |
|||
{ |
|||
#region Members
|
|||
|
|||
/// <summary>
|
|||
/// Flags if the Text and Value properties are in the process of being sync'd
|
|||
/// </summary>
|
|||
private bool _isSyncingTextAndValueProperties; |
|||
private bool _isInitialized; |
|||
private bool _convertExceptionOccurred = false; |
|||
|
|||
#endregion //Members
|
|||
|
|||
#region Properties
|
|||
|
|||
protected MaskedTextProvider MaskProvider |
|||
{ |
|||
get; |
|||
set; |
|||
} |
|||
|
|||
#region IncludePrompt
|
|||
|
|||
public static readonly DependencyProperty IncludePromptProperty = DependencyProperty.Register( "IncludePrompt", typeof( bool ), typeof( MaskedTextBox ), new UIPropertyMetadata( false, OnIncludePromptPropertyChanged ) ); |
|||
public bool IncludePrompt |
|||
{ |
|||
get |
|||
{ |
|||
return ( bool )GetValue( IncludePromptProperty ); |
|||
} |
|||
set |
|||
{ |
|||
SetValue( IncludePromptProperty, value ); |
|||
} |
|||
} |
|||
|
|||
private static void OnIncludePromptPropertyChanged( DependencyObject o, DependencyPropertyChangedEventArgs e ) |
|||
{ |
|||
MaskedTextBox maskedTextBox = o as MaskedTextBox; |
|||
if( maskedTextBox != null ) |
|||
maskedTextBox.OnIncludePromptChanged( ( bool )e.OldValue, ( bool )e.NewValue ); |
|||
} |
|||
|
|||
protected virtual void OnIncludePromptChanged( bool oldValue, bool newValue ) |
|||
{ |
|||
ResolveMaskProvider( Mask ); |
|||
} |
|||
|
|||
#endregion //IncludePrompt
|
|||
|
|||
#region IncludeLiterals
|
|||
|
|||
public static readonly DependencyProperty IncludeLiteralsProperty = DependencyProperty.Register( "IncludeLiterals", typeof( bool ), typeof( MaskedTextBox ), new UIPropertyMetadata( true, OnIncludeLiteralsPropertyChanged ) ); |
|||
public bool IncludeLiterals |
|||
{ |
|||
get |
|||
{ |
|||
return ( bool )GetValue( IncludeLiteralsProperty ); |
|||
} |
|||
set |
|||
{ |
|||
SetValue( IncludeLiteralsProperty, value ); |
|||
} |
|||
} |
|||
|
|||
private static void OnIncludeLiteralsPropertyChanged( DependencyObject o, DependencyPropertyChangedEventArgs e ) |
|||
{ |
|||
MaskedTextBox maskedTextBox = o as MaskedTextBox; |
|||
if( maskedTextBox != null ) |
|||
maskedTextBox.OnIncludeLiteralsChanged( ( bool )e.OldValue, ( bool )e.NewValue ); |
|||
} |
|||
|
|||
protected virtual void OnIncludeLiteralsChanged( bool oldValue, bool newValue ) |
|||
{ |
|||
ResolveMaskProvider( Mask ); |
|||
} |
|||
|
|||
#endregion //IncludeLiterals
|
|||
|
|||
#region Mask
|
|||
|
|||
public static readonly DependencyProperty MaskProperty = DependencyProperty.Register( "Mask", typeof( string ), typeof( MaskedTextBox ), new UIPropertyMetadata( "<>", OnMaskPropertyChanged ) ); |
|||
public string Mask |
|||
{ |
|||
get |
|||
{ |
|||
return ( string )GetValue( MaskProperty ); |
|||
} |
|||
set |
|||
{ |
|||
SetValue( MaskProperty, value ); |
|||
} |
|||
} |
|||
|
|||
private static void OnMaskPropertyChanged( DependencyObject o, DependencyPropertyChangedEventArgs e ) |
|||
{ |
|||
MaskedTextBox maskedTextBox = o as MaskedTextBox; |
|||
if( maskedTextBox != null ) |
|||
maskedTextBox.OnMaskChanged( ( string )e.OldValue, ( string )e.NewValue ); |
|||
} |
|||
|
|||
protected virtual void OnMaskChanged( string oldValue, string newValue ) |
|||
{ |
|||
ResolveMaskProvider( newValue ); |
|||
UpdateText( 0 ); |
|||
} |
|||
|
|||
#endregion //Mask
|
|||
|
|||
#region PromptChar
|
|||
|
|||
public static readonly DependencyProperty PromptCharProperty = DependencyProperty.Register( "PromptChar", typeof( char ), typeof( MaskedTextBox ), new UIPropertyMetadata( '_', OnPromptCharChanged ) ); |
|||
public char PromptChar |
|||
{ |
|||
get |
|||
{ |
|||
return ( char )GetValue( PromptCharProperty ); |
|||
} |
|||
set |
|||
{ |
|||
SetValue( PromptCharProperty, value ); |
|||
} |
|||
} |
|||
|
|||
private static void OnPromptCharChanged( DependencyObject o, DependencyPropertyChangedEventArgs e ) |
|||
{ |
|||
MaskedTextBox maskedTextBox = o as MaskedTextBox; |
|||
if( maskedTextBox != null ) |
|||
maskedTextBox.OnPromptCharChanged( ( char )e.OldValue, ( char )e.NewValue ); |
|||
} |
|||
|
|||
protected virtual void OnPromptCharChanged( char oldValue, char newValue ) |
|||
{ |
|||
ResolveMaskProvider( Mask ); |
|||
} |
|||
|
|||
#endregion //PromptChar
|
|||
|
|||
#region SelectAllOnGotFocus
|
|||
|
|||
public static readonly DependencyProperty SelectAllOnGotFocusProperty = DependencyProperty.Register( "SelectAllOnGotFocus", typeof( bool ), typeof( MaskedTextBox ), new PropertyMetadata( false ) ); |
|||
public bool SelectAllOnGotFocus |
|||
{ |
|||
get |
|||
{ |
|||
return ( bool )GetValue( SelectAllOnGotFocusProperty ); |
|||
} |
|||
set |
|||
{ |
|||
SetValue( SelectAllOnGotFocusProperty, value ); |
|||
} |
|||
} |
|||
|
|||
#endregion //SelectAllOnGotFocus
|
|||
|
|||
#region Text
|
|||
|
|||
private static void OnTextChanged( DependencyObject o, DependencyPropertyChangedEventArgs e ) |
|||
{ |
|||
MaskedTextBox inputBase = o as MaskedTextBox; |
|||
if( inputBase != null ) |
|||
inputBase.OnTextChanged( ( string )e.OldValue, ( string )e.NewValue ); |
|||
} |
|||
|
|||
protected virtual void OnTextChanged( string oldValue, string newValue ) |
|||
{ |
|||
if( _isInitialized ) |
|||
SyncTextAndValueProperties( MaskedTextBox.TextProperty, newValue ); |
|||
} |
|||
|
|||
#endregion //Text
|
|||
|
|||
#region Value
|
|||
|
|||
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register( "Value", typeof( object ), typeof( MaskedTextBox ), new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnValueChanged ) ); |
|||
public object Value |
|||
{ |
|||
get |
|||
{ |
|||
return ( object )GetValue( ValueProperty ); |
|||
} |
|||
set |
|||
{ |
|||
SetValue( ValueProperty, value ); |
|||
} |
|||
} |
|||
|
|||
private static void OnValueChanged( DependencyObject o, DependencyPropertyChangedEventArgs e ) |
|||
{ |
|||
MaskedTextBox maskedTextBox = o as MaskedTextBox; |
|||
if( maskedTextBox != null ) |
|||
maskedTextBox.OnValueChanged( ( object )e.OldValue, ( object )e.NewValue ); |
|||
} |
|||
|
|||
protected virtual void OnValueChanged( object oldValue, object newValue ) |
|||
{ |
|||
if( _isInitialized ) |
|||
SyncTextAndValueProperties( MaskedTextBox.ValueProperty, newValue ); |
|||
|
|||
RoutedPropertyChangedEventArgs<object> args = new RoutedPropertyChangedEventArgs<object>( oldValue, newValue ); |
|||
args.RoutedEvent = MaskedTextBox.ValueChangedEvent; |
|||
RaiseEvent( args ); |
|||
} |
|||
|
|||
#endregion //Value
|
|||
|
|||
#region ValueType
|
|||
|
|||
public static readonly DependencyProperty ValueTypeProperty = DependencyProperty.Register( "ValueType", typeof( Type ), typeof( MaskedTextBox ), new UIPropertyMetadata( typeof( String ), OnValueTypeChanged ) ); |
|||
public Type ValueType |
|||
{ |
|||
get |
|||
{ |
|||
return ( Type )GetValue( ValueTypeProperty ); |
|||
} |
|||
set |
|||
{ |
|||
SetValue( ValueTypeProperty, value ); |
|||
} |
|||
} |
|||
|
|||
private static void OnValueTypeChanged( DependencyObject o, DependencyPropertyChangedEventArgs e ) |
|||
{ |
|||
MaskedTextBox maskedTextBox = o as MaskedTextBox; |
|||
if( maskedTextBox != null ) |
|||
maskedTextBox.OnValueTypeChanged( ( Type )e.OldValue, ( Type )e.NewValue ); |
|||
} |
|||
|
|||
protected virtual void OnValueTypeChanged( Type oldValue, Type newValue ) |
|||
{ |
|||
if( _isInitialized ) |
|||
SyncTextAndValueProperties( MaskedTextBox.TextProperty, Text ); |
|||
} |
|||
|
|||
#endregion //ValueType
|
|||
|
|||
#endregion //Properties
|
|||
|
|||
#region Constructors
|
|||
|
|||
static MaskedTextBox() |
|||
{ |
|||
TextProperty.OverrideMetadata( typeof( MaskedTextBox ), new FrameworkPropertyMetadata( OnTextChanged ) ); |
|||
} |
|||
|
|||
public MaskedTextBox() |
|||
{ |
|||
CommandBindings.Add( new CommandBinding( ApplicationCommands.Paste, Paste ) ); //handle paste
|
|||
CommandBindings.Add( new CommandBinding( ApplicationCommands.Cut, null, CanCut ) ); //surpress cut
|
|||
} |
|||
|
|||
#endregion //Constructors
|
|||
|
|||
#region Base Class Overrides
|
|||
|
|||
public override void OnApplyTemplate() |
|||
{ |
|||
base.OnApplyTemplate(); |
|||
|
|||
ResolveMaskProvider( Mask ); |
|||
UpdateText( 0 ); |
|||
} |
|||
|
|||
protected override void OnInitialized( EventArgs e ) |
|||
{ |
|||
base.OnInitialized( e ); |
|||
|
|||
if( !_isInitialized ) |
|||
{ |
|||
_isInitialized = true; |
|||
SyncTextAndValueProperties( ValueProperty, Value ); |
|||
} |
|||
} |
|||
|
|||
protected override void OnGotKeyboardFocus( KeyboardFocusChangedEventArgs e ) |
|||
{ |
|||
if( SelectAllOnGotFocus ) |
|||
{ |
|||
SelectAll(); |
|||
} |
|||
|
|||
base.OnGotKeyboardFocus( e ); |
|||
} |
|||
|
|||
protected override void OnPreviewKeyDown( KeyEventArgs e ) |
|||
{ |
|||
if( !e.Handled ) |
|||
{ |
|||
HandlePreviewKeyDown( e ); |
|||
} |
|||
|
|||
base.OnPreviewKeyDown( e ); |
|||
} |
|||
|
|||
protected override void OnPreviewTextInput( TextCompositionEventArgs e ) |
|||
{ |
|||
if( !e.Handled ) |
|||
{ |
|||
HandlePreviewTextInput( e ); |
|||
} |
|||
|
|||
base.OnPreviewTextInput( e ); |
|||
} |
|||
|
|||
#endregion //Base Class Overrides
|
|||
|
|||
#region Events
|
|||
|
|||
public static readonly RoutedEvent ValueChangedEvent = EventManager.RegisterRoutedEvent( "ValueChanged", RoutingStrategy.Bubble, typeof( RoutedPropertyChangedEventHandler<object> ), typeof( MaskedTextBox ) ); |
|||
public event RoutedPropertyChangedEventHandler<object> ValueChanged |
|||
{ |
|||
add |
|||
{ |
|||
AddHandler( ValueChangedEvent, value ); |
|||
} |
|||
remove |
|||
{ |
|||
RemoveHandler( ValueChangedEvent, value ); |
|||
} |
|||
} |
|||
|
|||
#endregion //Events
|
|||
|
|||
#region Methods
|
|||
|
|||
#region Private
|
|||
|
|||
private void UpdateText() |
|||
{ |
|||
UpdateText( SelectionStart ); |
|||
} |
|||
|
|||
private void UpdateText( int position ) |
|||
{ |
|||
MaskedTextProvider provider = MaskProvider; |
|||
if( provider == null ) |
|||
throw new InvalidOperationException(); |
|||
|
|||
Text = provider.ToDisplayString(); |
|||
SelectionLength = 0; |
|||
SelectionStart = position; |
|||
} |
|||
|
|||
private int GetNextCharacterPosition( int startPosition ) |
|||
{ |
|||
int position = MaskProvider.FindEditPositionFrom( startPosition, true ); |
|||
return position == -1 ? startPosition : position; |
|||
} |
|||
|
|||
private void ResolveMaskProvider( string mask ) |
|||
{ |
|||
//do not create a mask provider if the Mask is empty, which can occur if the IncludePrompt and IncludeLiterals properties
|
|||
//are set prior to the Mask.
|
|||
if( String.IsNullOrEmpty( mask ) ) |
|||
return; |
|||
|
|||
MaskProvider = new MaskedTextProvider( mask ) |
|||
{ |
|||
IncludePrompt = this.IncludePrompt, |
|||
IncludeLiterals = this.IncludeLiterals, |
|||
PromptChar = this.PromptChar, |
|||
ResetOnSpace = false //should make this a property
|
|||
}; |
|||
} |
|||
|
|||
private object ConvertTextToValue( string text ) |
|||
{ |
|||
object convertedValue = null; |
|||
|
|||
Type dataType = ValueType; |
|||
|
|||
string valueToConvert = MaskProvider.ToString().Trim(); |
|||
|
|||
try |
|||
{ |
|||
if( valueToConvert.GetType() == dataType || dataType.IsInstanceOfType( valueToConvert ) ) |
|||
{ |
|||
convertedValue = valueToConvert; |
|||
} |
|||
#if !VS2008
|
|||
else if( String.IsNullOrWhiteSpace( valueToConvert ) ) |
|||
{ |
|||
convertedValue = Activator.CreateInstance( dataType ); |
|||
} |
|||
#else
|
|||
else if ( String.IsNullOrEmpty( valueToConvert ) ) |
|||
{ |
|||
convertedValue = Activator.CreateInstance( dataType ); |
|||
} |
|||
#endif
|
|||
else if( null == convertedValue && valueToConvert is IConvertible ) |
|||
{ |
|||
convertedValue = Convert.ChangeType( valueToConvert, dataType ); |
|||
} |
|||
} |
|||
catch |
|||
{ |
|||
//if an excpetion occurs revert back to original value
|
|||
_convertExceptionOccurred = true; |
|||
return Value; |
|||
} |
|||
|
|||
return convertedValue; |
|||
} |
|||
|
|||
private string ConvertValueToText( object value ) |
|||
{ |
|||
if( value == null ) |
|||
value = string.Empty; |
|||
|
|||
if( _convertExceptionOccurred ) |
|||
{ |
|||
value = Value; |
|||
_convertExceptionOccurred = false; |
|||
} |
|||
|
|||
//I have only seen this occur while in Blend, but we need it here so the Blend designer doesn't crash.
|
|||
if( MaskProvider == null ) |
|||
return value.ToString(); |
|||
|
|||
MaskProvider.Set( value.ToString() ); |
|||
return MaskProvider.ToDisplayString(); |
|||
} |
|||
|
|||
private void SyncTextAndValueProperties( DependencyProperty p, object newValue ) |
|||
{ |
|||
//prevents recursive syncing properties
|
|||
if( _isSyncingTextAndValueProperties ) |
|||
return; |
|||
|
|||
_isSyncingTextAndValueProperties = true; |
|||
|
|||
//this only occures when the user typed in the value
|
|||
if( MaskedTextBox.TextProperty == p ) |
|||
{ |
|||
if( newValue != null ) |
|||
SetValue( MaskedTextBox.ValueProperty, ConvertTextToValue( newValue.ToString() ) ); |
|||
} |
|||
|
|||
SetValue( MaskedTextBox.TextProperty, ConvertValueToText( newValue ) ); |
|||
|
|||
_isSyncingTextAndValueProperties = false; |
|||
} |
|||
|
|||
private void HandlePreviewTextInput( TextCompositionEventArgs e ) |
|||
{ |
|||
if( !IsReadOnly ) |
|||
{ |
|||
this.InsertText( e.Text ); |
|||
} |
|||
|
|||
e.Handled = true; |
|||
} |
|||
|
|||
private void HandlePreviewKeyDown( KeyEventArgs e ) |
|||
{ |
|||
if( e.Key == Key.Delete ) |
|||
{ |
|||
e.Handled = IsReadOnly |
|||
|| HandleKeyDownDelete(); |
|||
} |
|||
else if( e.Key == Key.Back ) |
|||
{ |
|||
e.Handled = IsReadOnly |
|||
|| HandleKeyDownBack(); |
|||
} |
|||
else if( e.Key == Key.Space ) |
|||
{ |
|||
if( !IsReadOnly ) |
|||
{ |
|||
InsertText( " " ); |
|||
} |
|||
|
|||
e.Handled = true; |
|||
} |
|||
else if( e.Key == Key.Return || e.Key == Key.Enter ) |
|||
{ |
|||
if( !IsReadOnly && AcceptsReturn ) |
|||
{ |
|||
this.InsertText( "\r" ); |
|||
} |
|||
|
|||
// We don't want the OnPreviewTextInput to be triggered for the Return/Enter key
|
|||
// when it is not accepted.
|
|||
e.Handled = true; |
|||
} |
|||
else if( e.Key == Key.Escape ) |
|||
{ |
|||
// We don't want the OnPreviewTextInput to be triggered at all for the Escape key.
|
|||
e.Handled = true; |
|||
} |
|||
else if( e.Key == Key.Tab ) |
|||
{ |
|||
if( AcceptsTab ) |
|||
{ |
|||
if( !IsReadOnly ) |
|||
{ |
|||
this.InsertText( "\t" ); |
|||
} |
|||
|
|||
e.Handled = true; |
|||
} |
|||
} |
|||
} |
|||
|
|||
private bool HandleKeyDownDelete() |
|||
{ |
|||
ModifierKeys modifiers = Keyboard.Modifiers; |
|||
bool handled = true; |
|||
|
|||
if( modifiers == ModifierKeys.None ) |
|||
{ |
|||
if( !RemoveSelectedText() ) |
|||
{ |
|||
int position = SelectionStart; |
|||
|
|||
if( position < Text.Length ) |
|||
{ |
|||
RemoveText( position, 1 ); |
|||
UpdateText( position ); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
UpdateText(); |
|||
} |
|||
} |
|||
else if( modifiers == ModifierKeys.Control ) |
|||
{ |
|||
if( !RemoveSelectedText() ) |
|||
{ |
|||
int position = SelectionStart; |
|||
|
|||
RemoveTextToEnd( position ); |
|||
UpdateText( position ); |
|||
} |
|||
else |
|||
{ |
|||
UpdateText(); |
|||
} |
|||
} |
|||
else if( modifiers == ModifierKeys.Shift ) |
|||
{ |
|||
if( RemoveSelectedText() ) |
|||
{ |
|||
UpdateText(); |
|||
} |
|||
else |
|||
{ |
|||
handled = false; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
handled = false; |
|||
} |
|||
|
|||
return handled; |
|||
} |
|||
|
|||
private bool HandleKeyDownBack() |
|||
{ |
|||
ModifierKeys modifiers = Keyboard.Modifiers; |
|||
bool handled = true; |
|||
|
|||
if( modifiers == ModifierKeys.None || modifiers == ModifierKeys.Shift ) |
|||
{ |
|||
if( !RemoveSelectedText() ) |
|||
{ |
|||
int position = SelectionStart; |
|||
|
|||
if( position > 0 ) |
|||
{ |
|||
int newPosition = position - 1; |
|||
|
|||
RemoveText( newPosition, 1 ); |
|||
UpdateText( newPosition ); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
UpdateText(); |
|||
} |
|||
} |
|||
else if( modifiers == ModifierKeys.Control ) |
|||
{ |
|||
if( !RemoveSelectedText() ) |
|||
{ |
|||
RemoveTextFromStart( SelectionStart ); |
|||
UpdateText( 0 ); |
|||
} |
|||
else |
|||
{ |
|||
UpdateText(); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
handled = false; |
|||
} |
|||
|
|||
return handled; |
|||
} |
|||
|
|||
private void InsertText( string text ) |
|||
{ |
|||
int position = SelectionStart; |
|||
MaskedTextProvider provider = MaskProvider; |
|||
|
|||
bool textRemoved = this.RemoveSelectedText(); |
|||
|
|||
position = GetNextCharacterPosition( position ); |
|||
|
|||
if( !textRemoved && Keyboard.IsKeyToggled( Key.Insert ) ) |
|||
{ |
|||
if( provider.Replace( text, position ) ) |
|||
{ |
|||
position += text.Length; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
if( provider.InsertAt( text, position ) ) |
|||
{ |
|||
position += text.Length; |
|||
} |
|||
} |
|||
|
|||
position = GetNextCharacterPosition( position ); |
|||
|
|||
this.UpdateText( position ); |
|||
} |
|||
|
|||
private void RemoveTextFromStart( int endPosition ) |
|||
{ |
|||
RemoveText( 0, endPosition ); |
|||
} |
|||
|
|||
private void RemoveTextToEnd( int startPosition ) |
|||
{ |
|||
RemoveText( startPosition, Text.Length - startPosition ); |
|||
} |
|||
|
|||
private void RemoveText( int position, int length ) |
|||
{ |
|||
if( length == 0 ) |
|||
return; |
|||
|
|||
MaskProvider.RemoveAt( position, position + length - 1 ); |
|||
} |
|||
|
|||
private bool RemoveSelectedText() |
|||
{ |
|||
int length = SelectionLength; |
|||
|
|||
if( length == 0 ) |
|||
return false; |
|||
|
|||
int position = SelectionStart; |
|||
|
|||
return MaskProvider.RemoveAt( position, position + length - 1 ); |
|||
} |
|||
|
|||
#endregion //Private
|
|||
|
|||
#endregion //Methods
|
|||
|
|||
#region Commands
|
|||
|
|||
private void Paste( object sender, RoutedEventArgs e ) |
|||
{ |
|||
if( IsReadOnly ) |
|||
return; |
|||
|
|||
object data = Clipboard.GetData( DataFormats.Text ); |
|||
if( data != null ) |
|||
{ |
|||
string text = data.ToString().Trim(); |
|||
if( text.Length > 0 ) |
|||
{ |
|||
int position = SelectionStart; |
|||
|
|||
MaskProvider.Set( text ); |
|||
|
|||
UpdateText( position ); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private void CanCut( object sender, CanExecuteRoutedEventArgs e ) |
|||
{ |
|||
e.CanExecute = false; |
|||
e.Handled = true; |
|||
} |
|||
|
|||
#endregion //Commands
|
|||
} |
|||
} |
|||
@ -0,0 +1,92 @@ |
|||
/************************************************************************ |
|||
|
|||
Extended WPF Toolkit |
|||
|
|||
Copyright (C) 2010-2012 Xceed Software Inc. |
|||
|
|||
This program is provided to you under the terms of the Microsoft Public |
|||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
|||
|
|||
This program can be provided to you by Xceed Software Inc. under a |
|||
proprietary commercial license agreement for use in non-Open Source |
|||
projects. The commercial version of Extended WPF Toolkit also includes |
|||
priority technical support, commercial updates, and many additional |
|||
useful WPF controls if you license Xceed Business Suite for WPF. |
|||
|
|||
Visit http://xceed.com and follow @datagrid on Twitter.
|
|||
|
|||
**********************************************************************/ |
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Windows.Data; |
|||
using System.Globalization; |
|||
using System.ComponentModel; |
|||
using System.Windows; |
|||
using System.Reflection; |
|||
|
|||
namespace Xceed.Wpf.Toolkit.PropertyGrid.Converters |
|||
{ |
|||
public class SelectedObjectConverter : IValueConverter |
|||
{ |
|||
private const string ValidParameterMessage = @"parameter must be one of the following strings: 'Type', 'TypeName'"; |
|||
#region IValueConverter Members
|
|||
|
|||
public object Convert( object value, Type targetType, object parameter, CultureInfo culture ) |
|||
{ |
|||
if( parameter == null ) |
|||
throw new ArgumentNullException( "parameter" ); |
|||
|
|||
if( !( parameter is string ) ) |
|||
throw new ArgumentException( SelectedObjectConverter.ValidParameterMessage ); |
|||
|
|||
if( this.CompareParam(parameter, "Type") ) |
|||
{ |
|||
return this.ConvertToType( value, culture ); |
|||
} |
|||
else if( this.CompareParam( parameter, "TypeName" ) ) |
|||
{ |
|||
return this.ConvertToTypeName( value, culture ); |
|||
} |
|||
else |
|||
{ |
|||
throw new ArgumentException( SelectedObjectConverter.ValidParameterMessage ); |
|||
} |
|||
} |
|||
|
|||
private bool CompareParam(object parameter, string parameterValue ) |
|||
{ |
|||
return string.Compare( ( string )parameter, parameterValue, true ) == 0; |
|||
} |
|||
|
|||
private object ConvertToType( object value, CultureInfo culture ) |
|||
{ |
|||
return ( value != null ) |
|||
? value.GetType() |
|||
: null; |
|||
} |
|||
|
|||
private object ConvertToTypeName( object value, CultureInfo culture ) |
|||
{ |
|||
if( value == null ) |
|||
return string.Empty; |
|||
|
|||
Type newType = value.GetType(); |
|||
|
|||
DisplayNameAttribute displayNameAttribute = newType.GetCustomAttributes( false ).OfType<DisplayNameAttribute>().FirstOrDefault(); |
|||
|
|||
return (displayNameAttribute == null) |
|||
? newType.Name |
|||
: displayNameAttribute.DisplayName; |
|||
} |
|||
|
|||
public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture ) |
|||
{ |
|||
throw new NotImplementedException(); |
|||
} |
|||
|
|||
#endregion
|
|||
} |
|||
} |
|||
@ -0,0 +1,52 @@ |
|||
/************************************************************************ |
|||
|
|||
Extended WPF Toolkit |
|||
|
|||
Copyright (C) 2010-2012 Xceed Software Inc. |
|||
|
|||
This program is provided to you under the terms of the Microsoft Public |
|||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
|||
|
|||
This program can be provided to you by Xceed Software Inc. under a |
|||
proprietary commercial license agreement for use in non-Open Source |
|||
projects. The commercial version of Extended WPF Toolkit also includes |
|||
priority technical support, commercial updates, and many additional |
|||
useful WPF controls if you license Xceed Business Suite for WPF. |
|||
|
|||
Visit http://xceed.com and follow @datagrid on Twitter.
|
|||
|
|||
**********************************************************************/ |
|||
|
|||
using Xceed.Wpf.Toolkit.Primitives; |
|||
using System; |
|||
namespace Xceed.Wpf.Toolkit.PropertyGrid.Editors |
|||
{ |
|||
public class UpDownEditor<TEditor, TType> : TypeEditor<TEditor> where TEditor : UpDownBase<TType>, new() |
|||
{ |
|||
protected override void SetControlProperties() |
|||
{ |
|||
Editor.BorderThickness = new System.Windows.Thickness( 0 ); |
|||
} |
|||
protected override void SetValueDependencyProperty() |
|||
{ |
|||
ValueProperty = UpDownBase<TType>.ValueProperty; |
|||
} |
|||
} |
|||
|
|||
public class ByteUpDownEditor : UpDownEditor<ByteUpDown, byte?> { } |
|||
|
|||
public class DecimalUpDownEditor : UpDownEditor<DecimalUpDown, decimal?> { } |
|||
|
|||
public class DoubleUpDownEditor : UpDownEditor<DoubleUpDown, double?> { } |
|||
|
|||
public class IntegerUpDownEditor : UpDownEditor<IntegerUpDown, int?> { } |
|||
|
|||
public class LongUpDownEditor : UpDownEditor<LongUpDown, long?> { } |
|||
|
|||
public class ShortUpDownEditor : UpDownEditor<ShortUpDown, short?> { } |
|||
|
|||
public class SingleUpDownEditor : UpDownEditor<SingleUpDown, float?> { } |
|||
|
|||
public class DateTimeUpDownEditor : UpDownEditor<DateTimeUpDown, DateTime?> { } |
|||
|
|||
} |
|||
@ -0,0 +1,36 @@ |
|||
/************************************************************************ |
|||
|
|||
Extended WPF Toolkit |
|||
|
|||
Copyright (C) 2010-2012 Xceed Software Inc. |
|||
|
|||
This program is provided to you under the terms of the Microsoft Public |
|||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
|||
|
|||
This program can be provided to you by Xceed Software Inc. under a |
|||
proprietary commercial license agreement for use in non-Open Source |
|||
projects. The commercial version of Extended WPF Toolkit also includes |
|||
priority technical support, commercial updates, and many additional |
|||
useful WPF controls if you license Xceed Business Suite for WPF. |
|||
|
|||
Visit http://xceed.com and follow @datagrid on Twitter.
|
|||
|
|||
**********************************************************************/ |
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using Xceed.Wpf.Toolkit.PropertyGrid.Attributes; |
|||
|
|||
namespace Xceed.Wpf.Toolkit.PropertyGrid |
|||
{ |
|||
internal interface IPropertyParent |
|||
{ |
|||
bool IsReadOnly { get; } |
|||
|
|||
object ValueInstance { get; } |
|||
|
|||
EditorDefinitionCollection EditorDefinitions { get; } |
|||
} |
|||
} |
|||
@ -0,0 +1,288 @@ |
|||
/************************************************************************ |
|||
|
|||
Extended WPF Toolkit |
|||
|
|||
Copyright (C) 2010-2012 Xceed Software Inc. |
|||
|
|||
This program is provided to you under the terms of the Microsoft Public |
|||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
|||
|
|||
This program can be provided to you by Xceed Software Inc. under a |
|||
proprietary commercial license agreement for use in non-Open Source |
|||
projects. The commercial version of Extended WPF Toolkit also includes |
|||
priority technical support, commercial updates, and many additional |
|||
useful WPF controls if you license Xceed Business Suite for WPF. |
|||
|
|||
Visit http://xceed.com and follow @datagrid on Twitter.
|
|||
|
|||
**********************************************************************/ |
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.ComponentModel; |
|||
|
|||
namespace Xceed.Wpf.DataGrid |
|||
{ |
|||
/// <summary>
|
|||
/// This object is used as the dataItem of a VirtualItemInfo when creating a VirtualItemPage and waiting for the
|
|||
/// fetch callback.
|
|||
/// </summary>
|
|||
internal class EmptyDataItem : INotifyPropertyChanged, ICustomTypeDescriptor |
|||
{ |
|||
#region CONSTRUCTORS
|
|||
|
|||
internal EmptyDataItem() |
|||
: base() |
|||
{ |
|||
} |
|||
|
|||
internal EmptyDataItem( int index, VirtualList parentVirtualList ) |
|||
: base() |
|||
{ |
|||
if( index < 0 ) |
|||
throw new ArgumentException( "Index must be greater than or equal to zero.", "index" ); |
|||
|
|||
if( parentVirtualList == null ) |
|||
throw new ArgumentNullException( "parentVirtualList" ); |
|||
|
|||
m_index = index; |
|||
m_parentVirtualList = parentVirtualList; |
|||
} |
|||
|
|||
#endregion CONSTRUCTORS
|
|||
|
|||
#region Index Property
|
|||
|
|||
public int Index |
|||
{ |
|||
get |
|||
{ |
|||
return m_index; |
|||
} |
|||
} |
|||
|
|||
#endregion Index Property
|
|||
|
|||
#region INTERNAL PROPERTIES
|
|||
|
|||
internal VirtualList ParentVirtualList |
|||
{ |
|||
get |
|||
{ |
|||
return m_parentVirtualList; |
|||
} |
|||
} |
|||
|
|||
#endregion INTERNAL PROPERTIES
|
|||
|
|||
#region Indexer
|
|||
|
|||
[EditorBrowsable( EditorBrowsableState.Never )] |
|||
public object this[ object parameter ] |
|||
{ |
|||
get |
|||
{ |
|||
return null; |
|||
} |
|||
set |
|||
{ |
|||
} |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region PRIVATE FIELDS
|
|||
|
|||
private int m_index; |
|||
private VirtualList m_parentVirtualList; |
|||
|
|||
#endregion PRIVATE FIELDS
|
|||
|
|||
#region CONSTANTS
|
|||
|
|||
private static readonly EmptyDataItemPropertyDescriptorCollection DefaultEmptyDataItemPropertyDescriptorCollection = new EmptyDataItemPropertyDescriptorCollection(); |
|||
|
|||
#endregion CONSTANTS
|
|||
|
|||
#region ICustomTypeDescriptor Members
|
|||
|
|||
public AttributeCollection GetAttributes() |
|||
{ |
|||
return TypeDescriptor.GetAttributes( this ); |
|||
} |
|||
|
|||
public string GetClassName() |
|||
{ |
|||
return TypeDescriptor.GetClassName( this ); |
|||
} |
|||
|
|||
public string GetComponentName() |
|||
{ |
|||
return TypeDescriptor.GetComponentName( this ); |
|||
} |
|||
|
|||
public TypeConverter GetConverter() |
|||
{ |
|||
return TypeDescriptor.GetConverter( this ); |
|||
} |
|||
|
|||
public EventDescriptor GetDefaultEvent() |
|||
{ |
|||
return TypeDescriptor.GetDefaultEvent( this ); |
|||
} |
|||
|
|||
public PropertyDescriptor GetDefaultProperty() |
|||
{ |
|||
return TypeDescriptor.GetDefaultProperty( this ); |
|||
} |
|||
|
|||
public object GetEditor( Type editorBaseType ) |
|||
{ |
|||
return TypeDescriptor.GetEditor( this, editorBaseType ); |
|||
} |
|||
|
|||
public EventDescriptorCollection GetEvents( Attribute[] attributes ) |
|||
{ |
|||
return TypeDescriptor.GetEvents( this, attributes ); |
|||
} |
|||
|
|||
public EventDescriptorCollection GetEvents() |
|||
{ |
|||
return TypeDescriptor.GetEvents( this ); |
|||
} |
|||
|
|||
public PropertyDescriptorCollection GetProperties( Attribute[] attributes ) |
|||
{ |
|||
// We use a custom PropertyDescriptorCollection that will return the same instance
|
|||
// of an EmptyDataItemPropertyDescriptor for ANY property that will be ask. This is to avoid
|
|||
// BindingErrors when an EmptyDataItem is used in the grid.
|
|||
return EmptyDataItem.DefaultEmptyDataItemPropertyDescriptorCollection; |
|||
} |
|||
|
|||
public PropertyDescriptorCollection GetProperties() |
|||
{ |
|||
return this.GetProperties( null ); |
|||
} |
|||
|
|||
public object GetPropertyOwner( PropertyDescriptor pd ) |
|||
{ |
|||
return this; |
|||
} |
|||
|
|||
#endregion ICustomTypeDescriptor Members
|
|||
|
|||
#region EmptyDataItemPropertyDescriptorCollection Class
|
|||
|
|||
private class EmptyDataItemPropertyDescriptorCollection : PropertyDescriptorCollection |
|||
{ |
|||
private static readonly EmptyDataItemPropertyDescriptor DefaultEmptyDataItemPropertyDescriptor = new EmptyDataItemPropertyDescriptor(); |
|||
|
|||
private static readonly EmptyDataItemPropertyDescriptor[] DefaultEmptyDataItemPropertyDescriptorArray = new EmptyDataItemPropertyDescriptor[] |
|||
{ |
|||
EmptyDataItemPropertyDescriptorCollection.DefaultEmptyDataItemPropertyDescriptor, |
|||
}; |
|||
|
|||
public EmptyDataItemPropertyDescriptorCollection() |
|||
: base( EmptyDataItemPropertyDescriptorCollection.DefaultEmptyDataItemPropertyDescriptorArray ) |
|||
{ |
|||
} |
|||
|
|||
public override PropertyDescriptor Find( string name, bool ignoreCase ) |
|||
{ |
|||
return EmptyDataItemPropertyDescriptorCollection.DefaultEmptyDataItemPropertyDescriptor; |
|||
} |
|||
|
|||
public override PropertyDescriptor this[ int index ] |
|||
{ |
|||
get |
|||
{ |
|||
return EmptyDataItemPropertyDescriptorCollection.DefaultEmptyDataItemPropertyDescriptor; |
|||
} |
|||
} |
|||
|
|||
public override PropertyDescriptor this[ string name ] |
|||
{ |
|||
get |
|||
{ |
|||
return EmptyDataItemPropertyDescriptorCollection.DefaultEmptyDataItemPropertyDescriptor; |
|||
} |
|||
} |
|||
} |
|||
|
|||
#endregion EmptyDataItemPropertyDescriptorCollection Class
|
|||
|
|||
#region EmptyDataItemPropertyDescriptor Class
|
|||
|
|||
private class EmptyDataItemPropertyDescriptor : PropertyDescriptor |
|||
{ |
|||
private const string DefaultPropertyName = "Empty"; |
|||
private static readonly Type ObjectType = typeof( object ); |
|||
|
|||
public EmptyDataItemPropertyDescriptor() |
|||
: base( EmptyDataItemPropertyDescriptor.DefaultPropertyName, null ) |
|||
{ |
|||
} |
|||
|
|||
public override bool CanResetValue( object component ) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
public override Type ComponentType |
|||
{ |
|||
get |
|||
{ |
|||
return EmptyDataItemPropertyDescriptor.ObjectType; |
|||
} |
|||
} |
|||
|
|||
public override object GetValue( object component ) |
|||
{ |
|||
return null; |
|||
} |
|||
|
|||
public override bool IsReadOnly |
|||
{ |
|||
get |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
public override Type PropertyType |
|||
{ |
|||
get |
|||
{ |
|||
return EmptyDataItemPropertyDescriptor.ObjectType; |
|||
} |
|||
} |
|||
|
|||
public override void ResetValue( object component ) |
|||
{ |
|||
} |
|||
|
|||
public override void SetValue( object component, object value ) |
|||
{ |
|||
} |
|||
|
|||
public override bool ShouldSerializeValue( object component ) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
#endregion EmptyDataItemPropertyDescriptor Class
|
|||
|
|||
#region INotifyPropertyChanged Members
|
|||
|
|||
event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged |
|||
{ |
|||
add { } |
|||
remove { } |
|||
} |
|||
|
|||
#endregion
|
|||
} |
|||
} |
|||
@ -0,0 +1,956 @@ |
|||
/************************************************************************ |
|||
|
|||
Extended WPF Toolkit |
|||
|
|||
Copyright (C) 2010-2012 Xceed Software Inc. |
|||
|
|||
This program is provided to you under the terms of the Microsoft Public |
|||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
|||
|
|||
This program can be provided to you by Xceed Software Inc. under a |
|||
proprietary commercial license agreement for use in non-Open Source |
|||
projects. The commercial version of Extended WPF Toolkit also includes |
|||
priority technical support, commercial updates, and many additional |
|||
useful WPF controls if you license Xceed Business Suite for WPF. |
|||
|
|||
Visit http://xceed.com and follow @datagrid on Twitter.
|
|||
|
|||
**********************************************************************/ |
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Diagnostics; |
|||
using System.Collections.Specialized; |
|||
using System.Windows.Threading; |
|||
using System.Windows; |
|||
using System.Collections.ObjectModel; |
|||
using System.ComponentModel; |
|||
using System.Collections; |
|||
|
|||
namespace Xceed.Wpf.DataGrid |
|||
{ |
|||
internal class VirtualList : IList, IList<object>, INotifyCollectionChanged, IDisposable |
|||
{ |
|||
|
|||
#region CONSTRUCTORS
|
|||
|
|||
public VirtualList( VirtualPageManager pagingManager ) |
|||
: this( pagingManager, -1 ) |
|||
{ |
|||
} |
|||
|
|||
public VirtualList( VirtualPageManager pagingManager, int virtualCount ) |
|||
{ |
|||
if( pagingManager == null ) |
|||
throw new ArgumentNullException( "pagingManager" ); |
|||
|
|||
pagingManager.ManageList( this ); |
|||
|
|||
m_tableOfContent = new VirtualListTableOfContent( 8 ); |
|||
|
|||
m_virtualCount = virtualCount; |
|||
} |
|||
|
|||
#endregion CONSTRUCTORS
|
|||
|
|||
#region VirtualPagingManager Property
|
|||
|
|||
public VirtualPageManager PagingManager |
|||
{ |
|||
get |
|||
{ |
|||
return m_pagingManager; |
|||
} |
|||
} |
|||
|
|||
#endregion VirtualPagingManager Property
|
|||
|
|||
|
|||
|
|||
#region VirtualCount Property
|
|||
|
|||
public int VirtualCount |
|||
{ |
|||
get |
|||
{ |
|||
if( this.IsDisposed ) |
|||
return 0; |
|||
|
|||
if( m_virtualCount == -1 ) |
|||
this.QueryAndSetVirtualCount(); |
|||
|
|||
return m_virtualCount; |
|||
} |
|||
} |
|||
|
|||
#endregion VirtualCount Property
|
|||
|
|||
internal int IndexOf( object item ) |
|||
{ |
|||
if( ( item == null ) || ( this.IsDisposed ) ) |
|||
return -1; |
|||
|
|||
EmptyDataItem emptyDataItem = item as EmptyDataItem; |
|||
|
|||
if( emptyDataItem != null ) |
|||
{ |
|||
if( ( emptyDataItem.ParentVirtualList == this ) && ( emptyDataItem.Index < m_virtualCount ) ) |
|||
return emptyDataItem.Index; |
|||
|
|||
return -1; |
|||
} |
|||
|
|||
return m_tableOfContent.IndexOf( item ); |
|||
} |
|||
|
|||
#region PUBLIC METHODS
|
|||
|
|||
#if DEBUG
|
|||
public override string ToString() |
|||
{ |
|||
StringBuilder builder = new StringBuilder(); |
|||
|
|||
ReadOnlyCollection<VirtualPage> virtualPages = m_tableOfContent.VirtualPages; |
|||
int pageCount = virtualPages.Count; |
|||
|
|||
for( int i = 0; i < pageCount; i++ ) |
|||
{ |
|||
VirtualPage page = virtualPages[ i ]; |
|||
|
|||
builder.Append( i.ToString() + ": Page " + page.ToString() + Environment.NewLine ); |
|||
} |
|||
|
|||
return builder.ToString(); |
|||
} |
|||
#endif
|
|||
|
|||
#endregion PUBLIC METHODS
|
|||
|
|||
|
|||
#region INTERNAL PROPERTIES
|
|||
|
|||
internal VirtualListTableOfContent TableOfContent |
|||
{ |
|||
get |
|||
{ |
|||
return m_tableOfContent; |
|||
} |
|||
} |
|||
|
|||
internal VirtualPageManager VirtualPagingManager |
|||
{ |
|||
get |
|||
{ |
|||
return m_pagingManager; |
|||
} |
|||
set |
|||
{ |
|||
// null is an acceptable value when disposing the list
|
|||
if( ( m_pagingManager != null ) && ( value != null ) ) |
|||
throw new InvalidOperationException( "An attempt was made to set a VirtualPageManager when one has already been provided." ); |
|||
|
|||
m_pagingManager = value; |
|||
} |
|||
} |
|||
|
|||
|
|||
#endregion INTERNAL PROPERTIES
|
|||
|
|||
|
|||
#region INTERNAL METHODS
|
|||
|
|||
internal bool IsPageDirty( int index ) |
|||
{ |
|||
VirtualPage page = this.GetPageOrDefaultForItemIndex( index, true ); |
|||
|
|||
return ( page == null ) ? false : page.IsDirty; |
|||
} |
|||
|
|||
internal bool IsItemDirty( object item ) |
|||
{ |
|||
int localIndex = this.IndexOf( item ); |
|||
|
|||
if( localIndex == -1 ) |
|||
return false; |
|||
|
|||
VirtualizedItemInfo virtualizedItemInfo = this.GetVirtualizedItemInfoAtIndex( localIndex, false, true ); |
|||
|
|||
return ( virtualizedItemInfo == null ) ? false : virtualizedItemInfo.IsDirty; |
|||
} |
|||
|
|||
internal VirtualizedItemValueCollection GetCachedValuesForItemAtIndex( int index ) |
|||
{ |
|||
VirtualizedItemInfo virtualizedItemInfo = this.GetVirtualizedItemInfoAtIndex( index, false, true ); |
|||
|
|||
return ( virtualizedItemInfo == null ) ? null : virtualizedItemInfo.OldValues; |
|||
} |
|||
|
|||
internal void SetCachedValuesForItemAtIndex( int index, string[] names, object[] values ) |
|||
{ |
|||
VirtualizedItemInfo virtualizedItemInfo = this.GetVirtualizedItemInfoAtIndex( index, false, true ); |
|||
|
|||
if( virtualizedItemInfo == null ) |
|||
throw new ArgumentOutOfRangeException( "index", index, "No VirtualizedItemInfo can be found at the specified index." ); |
|||
|
|||
virtualizedItemInfo.OldValues = new VirtualizedItemValueCollection( names, values ); |
|||
} |
|||
|
|||
internal void ClearCachedValuesForItemAtIndex( int index ) |
|||
{ |
|||
VirtualizedItemInfo virtualizedItemInfo = this.GetVirtualizedItemInfoAtIndex( index, false, true ); |
|||
|
|||
if( virtualizedItemInfo == null ) |
|||
throw new ArgumentOutOfRangeException( "index", index, "No VirtualizedItemInfo can be found at the specified index." ); |
|||
|
|||
virtualizedItemInfo.OldValues = null; |
|||
} |
|||
|
|||
internal object GetItemAt( int index ) |
|||
{ |
|||
if( ( index < 0 ) || ( index >= m_virtualCount ) ) |
|||
throw new ArgumentOutOfRangeException( "Index", index, "index must be greater than or equal to zero and less than count." ); |
|||
|
|||
VirtualizedItemInfo virtualizedItemInfo = this.GetVirtualizedItemInfoAtIndex( index, true, false ); |
|||
return virtualizedItemInfo.DataItem; |
|||
} |
|||
|
|||
internal VirtualizedItemInfo GetVirtualizedItemInfoAtIndex( int index, bool createPageIfLineNotFound, bool preventMovePageToFront ) |
|||
{ |
|||
VirtualizedItemInfo virtualizedItemInfo = null; |
|||
|
|||
VirtualPage page = this.GetPageOrDefaultForItemIndex( index, preventMovePageToFront ); |
|||
|
|||
if( page != null ) |
|||
{ |
|||
virtualizedItemInfo = page.GetVirtualizedItemInfoAtIndex( index ); |
|||
|
|||
Debug.Assert( virtualizedItemInfo != null ); |
|||
|
|||
|
|||
//if( ( virtualizedItemInfo == null ) && ( createPageIfLineNotFound ) )
|
|||
//{
|
|||
// // No VirtualizedItemInfo was found at the requested index.
|
|||
// LinkedListNode<VirtualPage> firstPageNode = m_pageNodes.First;
|
|||
|
|||
// Debug.Assert( firstPageNode != null, "If the page is not null, there should be at least one page in the book." );
|
|||
|
|||
// if( firstPageNode.Value != page )
|
|||
// {
|
|||
//
|
|||
// page = this.CreateNewPage( index );
|
|||
|
|||
// virtualizedItemInfo = page.GetVirtualizedItemInfoAtIndex( index );
|
|||
// this.AddPageToFront( page );
|
|||
// }
|
|||
//}
|
|||
} |
|||
else if( createPageIfLineNotFound ) |
|||
{ |
|||
page = this.CreateNewPage( index ); |
|||
|
|||
virtualizedItemInfo = page.GetVirtualizedItemInfoAtIndex( index ); |
|||
m_pagingManager.AddPage( page, VirtualPageManager.PageInsertPosition.Front ); |
|||
} |
|||
|
|||
return virtualizedItemInfo; |
|||
} |
|||
|
|||
internal void LockPageForLocalIndex( int sourceIndex ) |
|||
{ |
|||
Debug.Assert( m_tableOfContent.ContainsPageForSourceIndex( sourceIndex ) ); |
|||
Debug.Assert( this.GetPageOrDefaultForItemIndex( sourceIndex, true ) != null ); |
|||
|
|||
VirtualPage page; |
|||
if( m_tableOfContent.TryGetPageForSourceIndex( sourceIndex, out page ) ) |
|||
{ |
|||
if( page.LockPage() ) |
|||
Debug.WriteLineIf( VirtualPageManager.DebugDataVirtualization, "List: " + this.GetHashCode().ToString() + " - LOCKING PAGE: " + page.ToString() + " for index: " + sourceIndex.ToString() + " NEW LOCKED PAGES COUNT: " + this.GetLockedPageCount().ToString() ); |
|||
|
|||
this.PreEmptiveLoadPages( sourceIndex, page ); |
|||
} |
|||
} |
|||
|
|||
internal void UnlockPageForLocalIndex( int sourceIndex ) |
|||
{ |
|||
if( this.IsDisposed ) |
|||
return; |
|||
|
|||
VirtualPage page; |
|||
|
|||
if( m_tableOfContent.TryGetPageForSourceIndex( sourceIndex, out page ) ) |
|||
{ |
|||
if( page.UnlockPage() ) |
|||
{ |
|||
Debug.Assert( this.GetLockedPageCount() >= 0 ); |
|||
|
|||
Debug.WriteLineIf( VirtualPageManager.DebugDataVirtualization, "List: " + this.GetHashCode().ToString() + " - UN-LOCKING PAGE: " + page.ToString() + " for index: " + sourceIndex.ToString() + " NEW LOCKED PAGES COUNT: " + this.GetLockedPageCount().ToString() ); |
|||
|
|||
m_pagingManager.CleanUpAndDisposeUnused(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private void PreEmptiveLoadPages( int sourceIndex, VirtualPage page ) |
|||
{ |
|||
// The VirtualList is disposed or part of a PagingManager
|
|||
// that will be disposed (only disconnected when dispose is required)
|
|||
if( !this.PagingManager.IsConnected ) |
|||
return; |
|||
|
|||
Debug.Assert( !this.IsDisposed ); |
|||
|
|||
double preemptivePageQueryRatio = m_pagingManager.PreemptivePageQueryRatio; |
|||
int pageSize = m_pagingManager.PageSize; |
|||
|
|||
double pageRatio = ( preemptivePageQueryRatio > 0.5 ) ? 0.5 : |
|||
( preemptivePageQueryRatio < 0.0 ) ? 0 : preemptivePageQueryRatio; |
|||
|
|||
double boundariesItemCount = ( pageRatio * pageSize ); |
|||
|
|||
int preEmptivePageStartIndex = -1; |
|||
|
|||
if( ( page.StartDataIndex > 0 ) && ( sourceIndex < ( page.StartDataIndex + boundariesItemCount ) ) ) |
|||
{ |
|||
// Pre emptively load the previous page.
|
|||
preEmptivePageStartIndex = page.StartDataIndex - pageSize; |
|||
} |
|||
else if( ( page.EndDataIndex < ( m_virtualCount - 1 ) ) && ( sourceIndex > ( page.EndDataIndex - boundariesItemCount ) ) ) |
|||
{ |
|||
// Pre emptively load the next page.
|
|||
preEmptivePageStartIndex = page.EndDataIndex + 1; |
|||
} |
|||
|
|||
if( preEmptivePageStartIndex != -1 ) |
|||
{ |
|||
VirtualPage preEmptivePage = null; |
|||
|
|||
// We do not want to move the pre-emptive page to the front if it is already created since it does not count as a
|
|||
// legitimate user-acess.
|
|||
preEmptivePage = this.GetPageOrDefaultForItemIndex( preEmptivePageStartIndex, true ); |
|||
|
|||
if( preEmptivePage == null ) |
|||
{ |
|||
// The pre-emptive page is not yet created. Let's do it and add it to the back since it is not really accessed at the moment.
|
|||
preEmptivePage = this.CreateNewPage( preEmptivePageStartIndex ); |
|||
m_pagingManager.AddPage( preEmptivePage, VirtualPageManager.PageInsertPosition.Back ); |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
internal bool IsAsyncCommitQueuedForItem( object item ) |
|||
{ |
|||
VirtualPage virtualPage; |
|||
|
|||
if( m_tableOfContent.TryGetPageForItem( item, out virtualPage ) ) |
|||
return virtualPage.IsAsyncCommitInfoQueuedForItem( item ); |
|||
|
|||
return false; |
|||
} |
|||
|
|||
internal void CommitAll() |
|||
{ |
|||
foreach( VirtualPage page in m_tableOfContent.VirtualPages ) |
|||
{ |
|||
Debug.Assert( page != null ); |
|||
Debug.Assert( page.ParentVirtualList == this ); |
|||
|
|||
if( page.IsDirty ) |
|||
m_pagingManager.QueueCommitData( page ); |
|||
} |
|||
} |
|||
|
|||
internal void Restart() |
|||
{ |
|||
if( this.IsRestarting ) |
|||
return; |
|||
|
|||
Debug.WriteLineIf( VirtualPageManager.DebugDataVirtualization, "Restart VirtualList requested, checking for pages to commit or abort..." ); |
|||
this.IsRestarting = true; |
|||
m_pagingManager.OnVirtualListRestarting( this ); |
|||
|
|||
// We must keep a copy since restarting can remove pages from table of content
|
|||
int virtualPagesCount = m_tableOfContent.VirtualPages.Count; |
|||
|
|||
if( virtualPagesCount == 0 ) |
|||
{ |
|||
this.EndRestart(); |
|||
} |
|||
else |
|||
{ |
|||
// Restart every pages this VirtualList contains
|
|||
|
|||
// Keep a reference to the pages that need to restart
|
|||
// in order to know when this VirtualList is restarted
|
|||
m_restartingPages.AddRange( m_tableOfContent.VirtualPages ); |
|||
|
|||
for( int i = virtualPagesCount - 1; i >= 0; i-- ) |
|||
{ |
|||
VirtualPage page = m_tableOfContent.VirtualPages[ i ]; |
|||
Debug.Assert( !page.IsDisposed ); |
|||
|
|||
if( !page.IsRestarting ) |
|||
page.Restart(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
internal void OnVirtualPageRestarting( VirtualPage page ) |
|||
{ |
|||
// Notify the VirtualPageManager that this page is restarted
|
|||
// to ensure it commits its data or aborts the QueryItems
|
|||
// if already invoked
|
|||
Debug.Assert( m_restartingPages.Contains( page ) ); |
|||
m_pagingManager.OnVirtualListPageRestarting( this, page ); |
|||
} |
|||
|
|||
internal void OnVirtualPageRestarted( VirtualPage page ) |
|||
{ |
|||
Debug.Assert( m_restartingPages.Contains( page ) ); |
|||
// The page is restarted, remove it from the restarting pages
|
|||
m_restartingPages.Remove( page ); |
|||
|
|||
// Notify the manager that this page is restarted in order
|
|||
// to let it remove it from its m_pageNodes and also
|
|||
// from this VirtualList TableOfContent.
|
|||
// NOTE: We do not remove it from the TableOfContent
|
|||
// immediately to avoid have to insert a condition in
|
|||
// VirtualPageManager.RemovePage since this method
|
|||
// used widely to ensure a page is removed from the
|
|||
// TableOfContent and from the m_pageNodes list.
|
|||
m_pagingManager.OnVirtualListPageRestarted( this, page ); |
|||
|
|||
// Ensure all restarted pages completed their commit or abort operation
|
|||
// before notifying that this list is restarted
|
|||
if( m_restartingPages.Count == 0 ) |
|||
{ |
|||
Debug.WriteLineIf( VirtualPageManager.DebugDataVirtualization, "Cleared VirtualList" ); |
|||
this.EndRestart(); |
|||
} |
|||
} |
|||
|
|||
#endregion INTERNAL METHODS
|
|||
|
|||
#region INTERNAL CALLBACKS METHODS
|
|||
|
|||
internal void FillEmptyPage( AsyncQueryInfo asyncQueryInfo, object[] fetchedItems ) |
|||
{ |
|||
// The VirtualList is disposed or part of a PagingManager
|
|||
// that will be disposed (only disconnected when dispose is required)
|
|||
if( !this.PagingManager.IsConnected ) |
|||
return; |
|||
|
|||
Debug.Assert( !this.IsDisposed ); |
|||
Debug.Assert( !asyncQueryInfo.IsDisposed ); |
|||
|
|||
// We do not want to move the page we are about to fill to the front since it does not count as a legitimate user-acess.
|
|||
// It will get moved to the front when one of its item is accessed.
|
|||
VirtualPage page = null; |
|||
page = this.GetPageOrDefaultForItemIndex( asyncQueryInfo.StartIndex, true ); |
|||
|
|||
// Although extremely rare, this situation could occur if we are calling RemovePageNode and the QueryData Dispatcher Operation
|
|||
// which has been asyncronously invoked in CreateNewPage is raising the QueryData event at the exact moment when we
|
|||
// try to abort the dispatcher operation. This means that the customer will have queued an async request for data
|
|||
// for a page we no longer care about, and have already removed from the Table of Content and our LinkedList.
|
|||
// This should NOT occur if the user did not abort the request and called the AsyncQueryInfo EndQuery method since AsyncQueryInfo should
|
|||
// not have invoked the EndQueryAction if its ShouldAbort property was set to true.
|
|||
if( page == null ) |
|||
return; |
|||
|
|||
Debug.Assert( !page.IsFilled ); |
|||
Debug.Assert( this.GetPageStartingIndexForItemIndex( asyncQueryInfo.StartIndex ) == asyncQueryInfo.StartIndex ); |
|||
|
|||
Debug.Assert( fetchedItems.Length <= page.Count ); |
|||
|
|||
if( fetchedItems.Length == page.Count ) |
|||
{ |
|||
object[] oldItems = page.ToItemArray(); |
|||
|
|||
m_tableOfContent.RemovePage( page ); |
|||
|
|||
page.EndQueryItems( asyncQueryInfo, fetchedItems ); |
|||
|
|||
m_tableOfContent.AddPage( page ); |
|||
|
|||
Debug.WriteLineIf( VirtualPageManager.DebugDataVirtualization, "Replaced TOC items/index for page: " + page.ToString() ); |
|||
|
|||
this.OnCollectionChanged( new NotifyCollectionChangedEventArgs( |
|||
NotifyCollectionChangedAction.Replace, |
|||
fetchedItems, oldItems, |
|||
asyncQueryInfo.StartIndex ) ); |
|||
} |
|||
else |
|||
{ |
|||
// The expected count was not met. Maybe the user told us the source was bigger than it really is, or maybe there
|
|||
// were delete operations made on the source since the last restart.
|
|||
//
|
|||
// Let's refresh the CollectionView.
|
|||
// This will restart the VirtualItemBook and raise the CollectionView's OnCollectionChanged Reset notification.
|
|||
this.OnCollectionChanged( new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Reset ) ); |
|||
} |
|||
} |
|||
|
|||
internal void NotifyCommitComplete( AsyncCommitInfo asyncCommitInfo ) |
|||
{ |
|||
if( asyncCommitInfo.VirtualizedItemInfos.Length < 1 ) |
|||
throw new DataGridInternalException(); |
|||
|
|||
int indexForItemInPage = asyncCommitInfo.VirtualizedItemInfos[ 0 ].Index; |
|||
|
|||
// We do not want to move the page we are about flag has committed to the front since it does not count as a legitimate user-access.
|
|||
// It will get moved to the front when one of its items is accessed.
|
|||
VirtualPage page = null; |
|||
page = this.GetPageOrDefaultForItemIndex( indexForItemInPage, true ); |
|||
|
|||
if( page == null ) |
|||
throw new InvalidOperationException( "An attempt was made to retrieve a page does not exist." ); |
|||
|
|||
if( ( !this.HasPagePendingCommit ) || ( !page.IsCommitPending ) ) |
|||
throw new InvalidOperationException( "An attempt was made to commit a page that does not have a pending commit operation." ); |
|||
|
|||
Debug.Assert( page.IsDirty ); |
|||
|
|||
page.EndCommitItems( asyncCommitInfo ); |
|||
|
|||
// If we no longer have any pages pending commit.
|
|||
if( !this.HasPagePendingCommit ) |
|||
{ |
|||
// CleanUp and queue a request to fill empty pages from the start of the queue.
|
|||
m_pagingManager.CleanUpAndDisposeUnused(); |
|||
|
|||
// This is a failsafe, to make sure that during the clean-up other commit were not queued.
|
|||
if( !this.HasPagePendingCommit ) |
|||
{ |
|||
if( !this.IsRestarting ) |
|||
{ |
|||
// After the call to cleanup, there should only be LOCKED pending fill pages remaining. Those are the one to refetch.
|
|||
List<VirtualPage> lockedPages = this.GetLockedPages(); |
|||
int lockedPageCount = lockedPages.Count; |
|||
|
|||
for( int i = 0; i < lockedPageCount; i++ ) |
|||
{ |
|||
VirtualPage lockedPage = lockedPages[ i ]; |
|||
|
|||
if( lockedPage.IsFilled ) |
|||
continue; |
|||
|
|||
// The locked page has been created while commit was pending. Let's queue its query data operation.
|
|||
m_pagingManager.QueueQueryData( lockedPage ); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
// We just completed the last commit operation for a Restart request.
|
|||
// Send another reset action which will in turn call another restart request.
|
|||
// This time, no pages should have to be committed and the restart will end correctly, synchronously with the reset.
|
|||
|
|||
//this.OnCollectionChanged( new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Reset ) );
|
|||
this.Restart(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
#endregion INTERNAL CALLBACKS METHODS
|
|||
|
|||
#region INTERNAL PROPERTIES
|
|||
|
|||
internal bool IsDisposed |
|||
{ |
|||
get |
|||
{ |
|||
return m_flags[ ( int )VirtualItemBookFlags.Disposed ]; |
|||
} |
|||
private set |
|||
{ |
|||
m_flags[ ( int )VirtualItemBookFlags.Disposed ] = value; |
|||
} |
|||
} |
|||
|
|||
internal bool IsRestarting |
|||
{ |
|||
get |
|||
{ |
|||
return m_flags[ ( int )VirtualItemBookFlags.Restarting ]; |
|||
} |
|||
private set |
|||
{ |
|||
m_flags[ ( int )VirtualItemBookFlags.Restarting ] = value; |
|||
} |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region PRIVATE PROPERTIES
|
|||
|
|||
internal bool HasPagePendingCommit |
|||
{ |
|||
get |
|||
{ |
|||
foreach( VirtualPage page in m_tableOfContent.VirtualPages ) |
|||
{ |
|||
if( page.IsCommitPending ) |
|||
return true; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
} |
|||
|
|||
#endregion PRIVATE PROPERTIES
|
|||
|
|||
#region PRIVATE METHODS
|
|||
|
|||
private void EndRestart() |
|||
{ |
|||
Debug.Assert( m_restartingPages.Count == 0 ); |
|||
m_virtualCount = -1; |
|||
this.IsRestarting = false; |
|||
|
|||
Debug.WriteLineIf( VirtualPageManager.DebugDataVirtualization, "VirtualList restarted" ); |
|||
|
|||
m_pagingManager.OnVirtualListRestarted( this ); |
|||
|
|||
this.Dispose(); |
|||
} |
|||
|
|||
private int GetPageStartingIndexForItemIndex( int itemIndex ) |
|||
{ |
|||
int pageSize = m_pagingManager.PageSize; |
|||
return ( itemIndex / pageSize ) * pageSize; |
|||
} |
|||
|
|||
private VirtualPage CreateNewPage( int itemIndex ) |
|||
{ |
|||
Debug.Assert( !m_tableOfContent.ContainsPageForSourceIndex( itemIndex ) ); |
|||
|
|||
int pageStartIndex = this.GetPageStartingIndexForItemIndex( itemIndex ); |
|||
|
|||
int pageSize = m_pagingManager.PageSize; |
|||
|
|||
int expectedItemCount = Math.Min( pageSize, ( m_virtualCount - pageStartIndex ) ); |
|||
expectedItemCount = Math.Max( 0, expectedItemCount ); |
|||
|
|||
VirtualPage page = VirtualPage.CreateEmptyPage( this, pageStartIndex, expectedItemCount ); |
|||
|
|||
m_tableOfContent.AddPage( page ); |
|||
|
|||
// If we have a pending commit page, this brandly new created page will get its query data queued when we are notified
|
|||
// of a commit completed and that we no longer have any pages awaiting commiting.
|
|||
if( !this.HasPagePendingCommit ) |
|||
m_pagingManager.QueueQueryData( page ); |
|||
|
|||
Debug.WriteLineIf( VirtualPageManager.DebugDataVirtualization, "Creating VirtualItemPlaceHolder for page: " + page.ToString() ); |
|||
return page; |
|||
} |
|||
|
|||
private VirtualPage GetPageOrDefaultForItemIndex( int index, bool preventMoveToFront ) |
|||
{ |
|||
VirtualPage page = null; |
|||
|
|||
if( m_tableOfContent.TryGetPageForSourceIndex( index, out page ) ) |
|||
{ |
|||
if( !preventMoveToFront ) |
|||
m_pagingManager.MovePageToFront( page ); |
|||
} |
|||
|
|||
return page; |
|||
} |
|||
|
|||
private int GetLockedPageCount() |
|||
{ |
|||
int lockedPageCount = 0; |
|||
|
|||
foreach( VirtualPage page in m_tableOfContent.VirtualPages ) |
|||
{ |
|||
Debug.Assert( page != null ); |
|||
|
|||
if( ( page != null ) && ( page.IsLocked ) ) |
|||
lockedPageCount++; |
|||
} |
|||
|
|||
return lockedPageCount; |
|||
} |
|||
|
|||
private List<VirtualPage> GetLockedPages() |
|||
{ |
|||
List<VirtualPage> lockedPages = new List<VirtualPage>(); |
|||
|
|||
foreach( VirtualPage page in m_tableOfContent.VirtualPages ) |
|||
{ |
|||
Debug.Assert( page != null ); |
|||
|
|||
if( ( page != null ) && ( page.IsLocked ) ) |
|||
lockedPages.Add( page ); |
|||
} |
|||
|
|||
return lockedPages; |
|||
} |
|||
|
|||
private void QueryAndSetVirtualCount() |
|||
{ |
|||
int count = m_pagingManager.OnQueryItemCount( this ); |
|||
|
|||
Debug.WriteLineIf( VirtualPageManager.DebugDataVirtualization, ( count != -1 ) ? "QUERY VIRTUAL COUNT: " + count.ToString() : "QUERY VIRTUAL COUNT NOT HANDLED, SETTING COUNT TO ZERO." ); |
|||
|
|||
if( count == -1 ) |
|||
count = 0; |
|||
|
|||
m_virtualCount = count; |
|||
} |
|||
|
|||
private void OnCollectionChanged( NotifyCollectionChangedEventArgs e ) |
|||
{ |
|||
if( this.CollectionChanged != null ) |
|||
this.CollectionChanged( this, e ); |
|||
} |
|||
|
|||
#endregion PRIVATE METHODS
|
|||
|
|||
#region PRIVATE FIELDS
|
|||
|
|||
private List<VirtualPage> m_restartingPages = new List<VirtualPage>(); |
|||
private VirtualPageManager m_pagingManager; |
|||
private BitVector32 m_flags; |
|||
private int m_virtualCount; |
|||
private VirtualListTableOfContent m_tableOfContent; |
|||
|
|||
#endregion PRIVATE FIELDS
|
|||
|
|||
|
|||
#region PRIVATE NESTED ENUMS
|
|||
|
|||
[Flags] |
|||
private enum VirtualItemBookFlags |
|||
{ |
|||
Restarting = 1, |
|||
Disposed = 2, |
|||
} |
|||
|
|||
#endregion PRIVATE NESTED ENUMS
|
|||
|
|||
|
|||
#region IList<object> Members
|
|||
|
|||
int IList<object>.IndexOf( object item ) |
|||
{ |
|||
return this.IndexOf( item ); |
|||
} |
|||
|
|||
void IList<object>.Insert( int index, object item ) |
|||
{ |
|||
throw new NotImplementedException(); |
|||
} |
|||
|
|||
void IList<object>.RemoveAt( int index ) |
|||
{ |
|||
throw new NotImplementedException(); |
|||
} |
|||
|
|||
object IList<object>.this[ int index ] |
|||
{ |
|||
get |
|||
{ |
|||
return this.GetItemAt( index ); |
|||
} |
|||
set |
|||
{ |
|||
throw new NotImplementedException(); |
|||
} |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region ICollection<object> Members
|
|||
|
|||
void ICollection<object>.Add( object item ) |
|||
{ |
|||
throw new NotImplementedException(); |
|||
} |
|||
|
|||
void ICollection<object>.Clear() |
|||
{ |
|||
throw new NotImplementedException(); |
|||
} |
|||
|
|||
bool ICollection<object>.Contains( object item ) |
|||
{ |
|||
return ( this.IndexOf( item ) != -1 ); |
|||
} |
|||
|
|||
void ICollection<object>.CopyTo( object[] array, int arrayIndex ) |
|||
{ |
|||
throw new NotImplementedException(); |
|||
} |
|||
|
|||
int ICollection<object>.Count |
|||
{ |
|||
get |
|||
{ |
|||
return this.VirtualCount; |
|||
} |
|||
} |
|||
|
|||
bool ICollection<object>.IsReadOnly |
|||
{ |
|||
get |
|||
{ |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
bool ICollection<object>.Remove( object item ) |
|||
{ |
|||
throw new NotImplementedException(); |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region IEnumerable<object> Members
|
|||
|
|||
IEnumerator<object> IEnumerable<object>.GetEnumerator() |
|||
{ |
|||
return new VirtualListEnumerator( this ); |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region IEnumerable Members
|
|||
|
|||
IEnumerator IEnumerable.GetEnumerator() |
|||
{ |
|||
return ( ( IEnumerable<object> )this ).GetEnumerator(); |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region INotifyCollectionChanged Members
|
|||
|
|||
public event NotifyCollectionChangedEventHandler CollectionChanged; |
|||
|
|||
#endregion
|
|||
|
|||
#region IList Members
|
|||
|
|||
int IList.Add( object value ) |
|||
{ |
|||
throw new NotImplementedException(); |
|||
} |
|||
|
|||
void IList.Clear() |
|||
{ |
|||
throw new NotImplementedException(); |
|||
} |
|||
|
|||
bool IList.Contains( object value ) |
|||
{ |
|||
return this.IndexOf( value ) != -1; |
|||
} |
|||
|
|||
int IList.IndexOf( object value ) |
|||
{ |
|||
return this.IndexOf( value ); |
|||
} |
|||
|
|||
void IList.Insert( int index, object value ) |
|||
{ |
|||
throw new NotImplementedException(); |
|||
} |
|||
|
|||
bool IList.IsFixedSize |
|||
{ |
|||
get |
|||
{ |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
bool IList.IsReadOnly |
|||
{ |
|||
get |
|||
{ |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
void IList.Remove( object value ) |
|||
{ |
|||
throw new NotImplementedException(); |
|||
} |
|||
|
|||
void IList.RemoveAt( int index ) |
|||
{ |
|||
throw new NotImplementedException(); |
|||
} |
|||
|
|||
object IList.this[ int index ] |
|||
{ |
|||
get |
|||
{ |
|||
return this.GetItemAt( index ); |
|||
} |
|||
set |
|||
{ |
|||
throw new NotImplementedException(); |
|||
} |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region ICollection Members
|
|||
|
|||
void ICollection.CopyTo( Array array, int index ) |
|||
{ |
|||
throw new NotImplementedException(); |
|||
} |
|||
|
|||
int ICollection.Count |
|||
{ |
|||
get |
|||
{ |
|||
return this.VirtualCount; |
|||
} |
|||
} |
|||
|
|||
bool ICollection.IsSynchronized |
|||
{ |
|||
get |
|||
{ |
|||
throw new NotImplementedException(); |
|||
} |
|||
} |
|||
|
|||
object ICollection.SyncRoot |
|||
{ |
|||
get |
|||
{ |
|||
throw new NotImplementedException(); |
|||
} |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
|
|||
|
|||
#region IDisposable Members
|
|||
|
|||
public void Dispose() |
|||
{ |
|||
|
|||
if( m_tableOfContent != null ) |
|||
{ |
|||
Debug.Assert( m_tableOfContent.VirtualPages.Count == 0 ); |
|||
m_tableOfContent.Dispose(); |
|||
m_tableOfContent = null; |
|||
} |
|||
|
|||
m_pagingManager = null; |
|||
this.IsDisposed = true; |
|||
|
|||
} |
|||
|
|||
#endregion
|
|||
} |
|||
} |
|||
@ -0,0 +1,157 @@ |
|||
/************************************************************************ |
|||
|
|||
Extended WPF Toolkit |
|||
|
|||
Copyright (C) 2010-2012 Xceed Software Inc. |
|||
|
|||
This program is provided to you under the terms of the Microsoft Public |
|||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
|||
|
|||
This program can be provided to you by Xceed Software Inc. under a |
|||
proprietary commercial license agreement for use in non-Open Source |
|||
projects. The commercial version of Extended WPF Toolkit also includes |
|||
priority technical support, commercial updates, and many additional |
|||
useful WPF controls if you license Xceed Business Suite for WPF. |
|||
|
|||
Visit http://xceed.com and follow @datagrid on Twitter.
|
|||
|
|||
**********************************************************************/ |
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Collections; |
|||
|
|||
namespace Xceed.Wpf.DataGrid |
|||
{ |
|||
internal class VirtualListEnumerator : IEnumerator<object>, IEnumerator |
|||
{ |
|||
public VirtualListEnumerator( VirtualList virtualList ) |
|||
{ |
|||
if( virtualList == null ) |
|||
throw new ArgumentNullException( "virtualList" ); |
|||
|
|||
m_virtualList = virtualList; |
|||
|
|||
m_version = m_virtualList.PagingManager.Version; |
|||
|
|||
m_orderedFilledVirtualPages = |
|||
m_virtualList.TableOfContent.VirtualPages.OrderBy( |
|||
virtualPage => virtualPage.StartDataIndex ).Where( |
|||
virtualPage => virtualPage.IsFilled ).ToArray(); |
|||
} |
|||
|
|||
#region INTERNAL PROPERTIES
|
|||
|
|||
internal bool BeforeStart |
|||
{ |
|||
get |
|||
{ |
|||
return m_beforeStart; |
|||
} |
|||
} |
|||
|
|||
internal bool AfterEnd |
|||
{ |
|||
get |
|||
{ |
|||
return m_afterEnd; |
|||
} |
|||
} |
|||
|
|||
#endregion INTERNAL PROPERTIES
|
|||
|
|||
#region IDisposable Members
|
|||
|
|||
public void Dispose() |
|||
{ |
|||
m_currentItemInfo = null; |
|||
m_orderedFilledVirtualPages = null; |
|||
m_virtualList = null; |
|||
} |
|||
|
|||
#endregion IDisposable Members
|
|||
|
|||
#region IEnumerator<object> Members
|
|||
|
|||
public object Current |
|||
{ |
|||
get |
|||
{ |
|||
return ( m_currentItemInfo == null ) ? null : m_currentItemInfo.DataItem; |
|||
} |
|||
} |
|||
|
|||
#endregion IEnumerator<object> Members
|
|||
|
|||
#region IEnumerator Members
|
|||
|
|||
object IEnumerator.Current |
|||
{ |
|||
get |
|||
{ |
|||
return ( m_currentItemInfo == null ) ? null : m_currentItemInfo.DataItem; |
|||
} |
|||
} |
|||
|
|||
public bool MoveNext() |
|||
{ |
|||
if( m_version != m_virtualList.PagingManager.Version ) |
|||
throw new InvalidOperationException( "TODO: Collection was modified." ); |
|||
|
|||
if( m_beforeStart ) |
|||
m_beforeStart = false; |
|||
|
|||
if( m_currentPageIndex < m_orderedFilledVirtualPages.Length ) |
|||
{ |
|||
VirtualPage virtualPage = m_orderedFilledVirtualPages[ m_currentPageIndex ]; |
|||
|
|||
m_currentItemInfo = virtualPage[ m_currentItemIndex ]; |
|||
|
|||
m_currentItemIndex++; |
|||
|
|||
if( m_currentItemIndex >= virtualPage.Count ) |
|||
{ |
|||
m_currentItemIndex = 0; |
|||
m_currentPageIndex++; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
else |
|||
{ |
|||
m_currentItemInfo = null; |
|||
m_afterEnd = true; |
|||
|
|||
return false; |
|||
} |
|||
} |
|||
|
|||
public void Reset() |
|||
{ |
|||
m_currentItemInfo = null; |
|||
m_currentItemIndex = 0; |
|||
m_currentPageIndex = 0; |
|||
m_afterEnd = false; |
|||
m_beforeStart = true; |
|||
} |
|||
|
|||
#endregion IEnumerator Members
|
|||
|
|||
#region PRIVATE FIELDS
|
|||
|
|||
private VirtualList m_virtualList; |
|||
private VirtualPage[] m_orderedFilledVirtualPages; |
|||
|
|||
private int m_version; |
|||
private VirtualizedItemInfo m_currentItemInfo; |
|||
private int m_currentPageIndex; |
|||
private int m_currentItemIndex; |
|||
|
|||
private bool m_beforeStart; |
|||
private bool m_afterEnd; |
|||
|
|||
#endregion PRIVATE FIELDS
|
|||
} |
|||
} |
|||
@ -0,0 +1,172 @@ |
|||
/************************************************************************ |
|||
|
|||
Extended WPF Toolkit |
|||
|
|||
Copyright (C) 2010-2012 Xceed Software Inc. |
|||
|
|||
This program is provided to you under the terms of the Microsoft Public |
|||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
|||
|
|||
This program can be provided to you by Xceed Software Inc. under a |
|||
proprietary commercial license agreement for use in non-Open Source |
|||
projects. The commercial version of Extended WPF Toolkit also includes |
|||
priority technical support, commercial updates, and many additional |
|||
useful WPF controls if you license Xceed Business Suite for WPF. |
|||
|
|||
Visit http://xceed.com and follow @datagrid on Twitter.
|
|||
|
|||
**********************************************************************/ |
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Diagnostics; |
|||
using System.Collections.ObjectModel; |
|||
|
|||
namespace Xceed.Wpf.DataGrid |
|||
{ |
|||
internal class VirtualListTableOfContent : IDisposable |
|||
{ |
|||
internal VirtualListTableOfContent( int initialCapacity ) |
|||
{ |
|||
m_virtualPages = new List<VirtualPage>(); |
|||
m_readonlyVirtualPages = new ReadOnlyCollection<VirtualPage>( m_virtualPages ); |
|||
|
|||
m_objectVersusIndexDictionary = new Dictionary<object, int>( initialCapacity ); |
|||
m_indexVersusPageDictionary = new Dictionary<int, VirtualPage>( initialCapacity ); |
|||
} |
|||
|
|||
public void AddPage( VirtualPage page ) |
|||
{ |
|||
Debug.Assert( !m_virtualPages.Contains( page ) ); |
|||
|
|||
m_virtualPages.Add( page ); |
|||
|
|||
int itemCount = page.Count; |
|||
|
|||
for( int i = 0; i < itemCount; i++ ) |
|||
{ |
|||
VirtualizedItemInfo virtualizedItemInfo = page[ i ]; |
|||
|
|||
Debug.Assert( !m_objectVersusIndexDictionary.ContainsKey( virtualizedItemInfo.DataItem ) ); |
|||
Debug.Assert( !m_indexVersusPageDictionary.ContainsKey( virtualizedItemInfo.Index ) ); |
|||
|
|||
m_objectVersusIndexDictionary.Add( virtualizedItemInfo.DataItem, virtualizedItemInfo.Index ); |
|||
m_indexVersusPageDictionary.Add( virtualizedItemInfo.Index, page ); |
|||
} |
|||
} |
|||
|
|||
public void RemovePage( VirtualPage page ) |
|||
{ |
|||
Debug.Assert( m_virtualPages.Contains( page ) ); |
|||
|
|||
int itemCount = page.Count; |
|||
|
|||
for( int i = 0; i < itemCount; i++ ) |
|||
{ |
|||
VirtualizedItemInfo virtualizedItemInfo = page[ i ]; |
|||
|
|||
Debug.Assert( m_objectVersusIndexDictionary.ContainsKey( virtualizedItemInfo.DataItem ) ); |
|||
Debug.Assert( m_indexVersusPageDictionary.ContainsKey( virtualizedItemInfo.Index ) ); |
|||
|
|||
Debug.Assert( m_indexVersusPageDictionary[ virtualizedItemInfo.Index ] == page ); |
|||
|
|||
m_objectVersusIndexDictionary.Remove( virtualizedItemInfo.DataItem ); |
|||
m_indexVersusPageDictionary.Remove( virtualizedItemInfo.Index ); |
|||
} |
|||
|
|||
m_virtualPages.Remove( page ); |
|||
} |
|||
|
|||
public int IndexOf( object item ) |
|||
{ |
|||
int index; |
|||
|
|||
if( m_objectVersusIndexDictionary.TryGetValue( item, out index ) ) |
|||
return index; |
|||
|
|||
return -1; |
|||
} |
|||
|
|||
public bool TryGetPageForItem( object item, out VirtualPage page ) |
|||
{ |
|||
page = null; |
|||
|
|||
int index; |
|||
|
|||
if( m_objectVersusIndexDictionary.TryGetValue( item, out index ) ) |
|||
return m_indexVersusPageDictionary.TryGetValue( index, out page ); |
|||
|
|||
return false; |
|||
} |
|||
|
|||
public bool TryGetPageForSourceIndex( int sourceIndex, out VirtualPage page ) |
|||
{ |
|||
return m_indexVersusPageDictionary.TryGetValue( sourceIndex, out page ); |
|||
} |
|||
|
|||
public bool ContainsPageForItem( object item ) |
|||
{ |
|||
int index; |
|||
|
|||
if( m_objectVersusIndexDictionary.TryGetValue( item, out index ) ) |
|||
return m_indexVersusPageDictionary.ContainsKey( index ); |
|||
|
|||
return false; |
|||
} |
|||
|
|||
public bool ContainsPageForSourceIndex( int sourceIndex ) |
|||
{ |
|||
return m_indexVersusPageDictionary.ContainsKey( sourceIndex ); |
|||
} |
|||
|
|||
public int Count |
|||
{ |
|||
get |
|||
{ |
|||
Debug.Assert( m_objectVersusIndexDictionary.Count == m_indexVersusPageDictionary.Count ); |
|||
return m_objectVersusIndexDictionary.Count; |
|||
} |
|||
} |
|||
|
|||
public ReadOnlyCollection<VirtualPage> VirtualPages |
|||
{ |
|||
get |
|||
{ |
|||
return m_readonlyVirtualPages; |
|||
} |
|||
} |
|||
|
|||
private Dictionary<object, int> m_objectVersusIndexDictionary; |
|||
private Dictionary<int, VirtualPage> m_indexVersusPageDictionary; |
|||
|
|||
private List<VirtualPage> m_virtualPages; |
|||
private ReadOnlyCollection<VirtualPage> m_readonlyVirtualPages; |
|||
|
|||
#region IDisposable Members
|
|||
|
|||
public void Dispose() |
|||
{ |
|||
while( m_virtualPages.Count > 0 ) |
|||
{ |
|||
// Remove the page from every Dictionaries and
|
|||
// also from m_virtualPages
|
|||
VirtualPage page = m_virtualPages[ 0 ]; |
|||
this.RemovePage( page ); |
|||
page.Dispose(); |
|||
} |
|||
|
|||
Debug.Assert( m_objectVersusIndexDictionary.Count == 0 ); |
|||
Debug.Assert( m_indexVersusPageDictionary.Count == 0 ); |
|||
Debug.Assert( m_virtualPages.Count == 0 ); |
|||
|
|||
m_objectVersusIndexDictionary.Clear(); |
|||
m_indexVersusPageDictionary.Clear(); |
|||
m_virtualPages.Clear(); |
|||
|
|||
} |
|||
|
|||
#endregion
|
|||
} |
|||
} |
|||
@ -0,0 +1,658 @@ |
|||
/************************************************************************ |
|||
|
|||
Extended WPF Toolkit |
|||
|
|||
Copyright (C) 2010-2012 Xceed Software Inc. |
|||
|
|||
This program is provided to you under the terms of the Microsoft Public |
|||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
|||
|
|||
This program can be provided to you by Xceed Software Inc. under a |
|||
proprietary commercial license agreement for use in non-Open Source |
|||
projects. The commercial version of Extended WPF Toolkit also includes |
|||
priority technical support, commercial updates, and many additional |
|||
useful WPF controls if you license Xceed Business Suite for WPF. |
|||
|
|||
Visit http://xceed.com and follow @datagrid on Twitter.
|
|||
|
|||
**********************************************************************/ |
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Diagnostics; |
|||
using System.Windows.Threading; |
|||
using System.Collections.Specialized; |
|||
|
|||
namespace Xceed.Wpf.DataGrid |
|||
{ |
|||
internal class VirtualPage |
|||
: List<VirtualizedItemInfo>, IDisposable |
|||
{ |
|||
#region CONSTRUCTORS
|
|||
|
|||
internal static VirtualPage CreateEmptyPage( VirtualList parentVirtualList, int startSourceIndex, int entryCount ) |
|||
{ |
|||
if( parentVirtualList == null ) |
|||
throw new ArgumentNullException( "parentVirtualList" ); |
|||
|
|||
if( startSourceIndex < 0 ) |
|||
throw new ArgumentOutOfRangeException( "startSourceIndex", startSourceIndex, "startSourceIndex must be greater than or equal to zero." ); |
|||
|
|||
if( entryCount < 0 ) |
|||
throw new ArgumentOutOfRangeException( "entryCount", entryCount, "entryCount must be greater than or equal to zero." ); |
|||
|
|||
EmptyDataItem[] emptyDataItems = new EmptyDataItem[ entryCount ]; |
|||
for( int i = 0; i < entryCount; i++ ) |
|||
{ |
|||
emptyDataItems[ i ] = new EmptyDataItem( startSourceIndex + i, parentVirtualList ); |
|||
} |
|||
|
|||
VirtualPage emptyDataItemPage = new VirtualPage( parentVirtualList, startSourceIndex, emptyDataItems ); |
|||
emptyDataItemPage.IsFilled = false; |
|||
|
|||
return emptyDataItemPage; |
|||
} |
|||
|
|||
private VirtualPage( VirtualList parentVirtualList, int startSourceIndex, object[] dataItems ) |
|||
: base( dataItems.Length ) |
|||
{ |
|||
if( parentVirtualList == null ) |
|||
throw new ArgumentNullException( "parentVirtualList" ); |
|||
|
|||
if( startSourceIndex < 0 ) |
|||
throw new ArgumentOutOfRangeException( "startSourceIndex", startSourceIndex, "startSourceIndex must be greater than or equal to zero." ); |
|||
|
|||
m_startDataIndex = startSourceIndex; |
|||
m_asyncCommitInfoList = new List<AsyncCommitInfo>(); |
|||
|
|||
m_parentVirtualList = parentVirtualList; |
|||
|
|||
int length = dataItems.Length; |
|||
for( int i = 0; i < length; i++ ) |
|||
{ |
|||
Debug.Assert( dataItems[ i ] != null ); |
|||
this.Add( new VirtualizedItemInfo( m_startDataIndex + i, dataItems[ i ] ) ); |
|||
} |
|||
|
|||
this.IsFilled = true; |
|||
} |
|||
|
|||
#endregion CONSTRUCTORS
|
|||
|
|||
#region RemoveAfterOperation
|
|||
|
|||
public bool RemoveAfterOperation |
|||
{ |
|||
get; |
|||
set; |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region IsAborting Property
|
|||
|
|||
public bool IsAborting |
|||
{ |
|||
get; |
|||
private set; |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region IsRestarting Property
|
|||
|
|||
public bool IsRestarting |
|||
{ |
|||
get; |
|||
private set; |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region IsEmpty Property
|
|||
|
|||
public bool IsEmpty |
|||
{ |
|||
get |
|||
{ |
|||
return ( this.Count == 0 ); |
|||
} |
|||
} |
|||
|
|||
#endregion IsEmpty Property
|
|||
|
|||
#region IsFilled Property
|
|||
|
|||
public bool IsFilled |
|||
{ |
|||
get |
|||
{ |
|||
return m_flags[ ( int )VirtualItemPageFlags.IsFilled ]; |
|||
} |
|||
private set |
|||
{ |
|||
// Wether we are setting PendingFill to True or to False, we should not be touching this property if we are pending commit.
|
|||
Debug.Assert( !this.IsCommitPending ); |
|||
|
|||
m_flags[ ( int )VirtualItemPageFlags.IsFilled ] = value; |
|||
} |
|||
} |
|||
|
|||
#endregion IsFilled Property
|
|||
|
|||
#region IsDisposed Read-Only Property
|
|||
|
|||
public bool IsDisposed |
|||
{ |
|||
get |
|||
{ |
|||
return m_flags[ ( int )VirtualItemPageFlags.IsDisposed ]; |
|||
} |
|||
private set |
|||
{ |
|||
m_flags[ ( int )VirtualItemPageFlags.IsDisposed ] = value; |
|||
} |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region IsCommitPending Property
|
|||
|
|||
public bool IsCommitPending |
|||
{ |
|||
get |
|||
{ |
|||
return m_asyncCommitInfoList.Count > 0; |
|||
} |
|||
} |
|||
|
|||
#endregion IsCommitPending Property
|
|||
|
|||
#region IsDirty Property
|
|||
|
|||
public bool IsDirty |
|||
{ |
|||
get |
|||
{ |
|||
if( !this.IsFilled ) |
|||
return false; |
|||
|
|||
int count = this.Count; |
|||
|
|||
for( int i = 0; i < count; i++ ) |
|||
{ |
|||
if( this[ i ].IsDirty ) |
|||
return true; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
} |
|||
|
|||
#endregion IsDirty Property
|
|||
|
|||
#region IsLocked Property
|
|||
|
|||
public bool IsLocked |
|||
{ |
|||
get |
|||
{ |
|||
return ( m_lockCount > 0 ); |
|||
} |
|||
} |
|||
|
|||
#endregion IsLocked Property
|
|||
|
|||
#region IsRemovable
|
|||
|
|||
public bool IsRemovable |
|||
{ |
|||
get |
|||
{ |
|||
// A page which IsPendingFill is removable since it hasn't even been filled yet.
|
|||
return ( ( !this.IsLocked ) && ( !this.IsCommitPending ) ); |
|||
} |
|||
} |
|||
|
|||
#endregion IsRemovable
|
|||
|
|||
#region ParentVirtualList Property
|
|||
|
|||
public VirtualList ParentVirtualList |
|||
{ |
|||
get |
|||
{ |
|||
return m_parentVirtualList; |
|||
} |
|||
} |
|||
|
|||
#endregion ParentVirtualList Property
|
|||
|
|||
|
|||
#region StartDataIndex Property
|
|||
|
|||
public int StartDataIndex |
|||
{ |
|||
get |
|||
{ |
|||
return m_startDataIndex; |
|||
} |
|||
} |
|||
|
|||
#endregion StartDataIndex Property
|
|||
|
|||
#region EndDataIndex Property
|
|||
|
|||
public int EndDataIndex |
|||
{ |
|||
get |
|||
{ |
|||
return m_startDataIndex + ( this.Count - 1 ); |
|||
} |
|||
} |
|||
|
|||
#endregion EndDataIndex Property
|
|||
|
|||
|
|||
#region PUBLIC METHODS
|
|||
|
|||
public VirtualizedItemInfo GetVirtualizedItemInfoAtIndex( int sourceIndex ) |
|||
{ |
|||
int index = this.SourceIndexToPageEntryIndex( sourceIndex ); |
|||
|
|||
if( index != -1 ) |
|||
return this[ index ]; |
|||
|
|||
return null; |
|||
} |
|||
|
|||
#if DEBUG
|
|||
public override string ToString() |
|||
{ |
|||
string representation = string.Empty; |
|||
|
|||
if( !this.IsFilled ) |
|||
representation += "Fill Pending - "; |
|||
|
|||
|
|||
if( this.IsEmpty ) |
|||
{ |
|||
representation += m_startDataIndex.ToString() + " - EMPTY."; |
|||
} |
|||
else |
|||
{ |
|||
representation += m_startDataIndex.ToString() + " - " + this.EndDataIndex.ToString(); |
|||
} |
|||
|
|||
return representation; |
|||
} |
|||
#endif
|
|||
|
|||
public object[] ToItemArray() |
|||
{ |
|||
int count = this.Count; |
|||
|
|||
object[] items = new object[ count ]; |
|||
|
|||
for( int i = 0; i < count; i++ ) |
|||
{ |
|||
items[ i ] = this[ i ].DataItem; |
|||
} |
|||
|
|||
return items; |
|||
} |
|||
|
|||
#endregion PUBLIC METHODS
|
|||
|
|||
|
|||
#region PRIVATE CALLBACKS
|
|||
|
|||
private void AsyncQueryInfo_BuiltInAbort( AsyncQueryInfo queryInfo ) |
|||
{ |
|||
this.ParentVirtualList.PagingManager.OnBuiltInAbort( this, queryInfo ); |
|||
this.IsAborting = false; |
|||
} |
|||
|
|||
private void AsyncQueryInfo_BeginQueryItems( AsyncQueryInfo queryInfo ) |
|||
{ |
|||
this.ParentVirtualList.PagingManager.OnQueryItems( this, queryInfo ); |
|||
} |
|||
|
|||
private void AsyncQueryInfo_AbortQueryItems( AsyncQueryInfo queryInfo ) |
|||
{ |
|||
if( this.IsDisposed ) |
|||
return; |
|||
|
|||
this.ParentVirtualList.PagingManager.OnAbortQueryItems( this, queryInfo ); |
|||
|
|||
this.IsAborting = false; |
|||
|
|||
// If the page was removed, it was also disposed.
|
|||
// This case means the page was not restarting
|
|||
if( !this.RemoveAfterOperation && this.ParentVirtualList.IsRestarting ) |
|||
this.Restart(); |
|||
} |
|||
|
|||
private void AsyncQueryInfo_EndQueryItems( AsyncQueryInfo queryInfo, object[] fetchedItems ) |
|||
{ |
|||
if( this.IsDisposed ) |
|||
return; |
|||
|
|||
Debug.Assert( !this.IsAborting ); |
|||
this.ParentVirtualList.PagingManager.OnQueryItemsCompleted( this, queryInfo, fetchedItems ); |
|||
|
|||
if( this.ParentVirtualList.IsRestarting ) |
|||
this.Restart(); |
|||
} |
|||
|
|||
private void AsyncQueryInfo_QueryErrorChanged( AsyncQueryInfo queryInfo ) |
|||
{ |
|||
this.ParentVirtualList.PagingManager.OnQueryErrorChanged( this, queryInfo ); |
|||
|
|||
if( this.ParentVirtualList.IsRestarting ) |
|||
this.Restart(); |
|||
} |
|||
|
|||
private void AsyncCommitInfo_BeginCommitItems( AsyncCommitInfo commitInfo ) |
|||
{ |
|||
this.ParentVirtualList.PagingManager.OnCommitItems( this, commitInfo ); |
|||
} |
|||
|
|||
private void AsyncCommitInfo_EndCommitItems( AsyncCommitInfo commitInfo ) |
|||
{ |
|||
this.ParentVirtualList.PagingManager.OnCommitItemsCompleted( this, commitInfo ); |
|||
|
|||
if( this.ParentVirtualList.IsRestarting ) |
|||
this.Restart(); |
|||
} |
|||
|
|||
private void AsyncCommitInfo_CommitErrorChanged( AsyncCommitInfo commitInfo ) |
|||
{ |
|||
this.ParentVirtualList.PagingManager.OnCommitErrorChanged( this, commitInfo ); |
|||
|
|||
if( this.ParentVirtualList.IsRestarting ) |
|||
this.Restart(); |
|||
} |
|||
|
|||
#endregion PRIVATE CALLBACKS
|
|||
|
|||
#region INTERNAL METHODS
|
|||
|
|||
/// <summary>
|
|||
/// Increments the page's lock count.
|
|||
/// Returns True if the lock count went from 0 to 1, meaning that the page is now considered locked and is not up for removal.
|
|||
/// </summary>
|
|||
internal bool LockPage() |
|||
{ |
|||
m_lockCount++; |
|||
|
|||
// Returns True if the page just became locked or False if the call simply incremented the lock count.
|
|||
return m_lockCount == 1; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Decrements the page's lock count.
|
|||
/// Returns True if the lock count is down to 0, meaning that the page is now considered unlocked and is up for removal.
|
|||
/// </summary>
|
|||
internal bool UnlockPage() |
|||
{ |
|||
if( m_lockCount > 0 ) |
|||
{ |
|||
m_lockCount--; |
|||
} |
|||
else |
|||
{ |
|||
// Safety Net. We return False, even though the lock count is reinitialized to zero, since the page did not just become unlocked.
|
|||
// This can occur when the DataGridVirtualizingCollectionView hits ForceRefresh method restarts the VirtualItemBook, thus getting rid
|
|||
// of locked and unlocked pages and THEN, the Generator's WeakEventListener of CollectionChanged cleans up its containers which in turn
|
|||
// tries to unlock a source index which isn't locked at all (since it was cleared when the virtual item book reseted).
|
|||
m_lockCount = 0; |
|||
return false; |
|||
} |
|||
|
|||
// Returns True if the page just became unlocked or False if the call simply decremented the lock count.
|
|||
return m_lockCount == 0; |
|||
} |
|||
|
|||
internal void AbortQueryDataOperation() |
|||
{ |
|||
Debug.Assert( !this.IsDisposed ); |
|||
|
|||
if( this.IsFilled ) |
|||
throw new InvalidOperationException( "An attempt was made to abort a query that has already completed." ); |
|||
|
|||
if( m_asyncQueryInfo != null ) |
|||
{ |
|||
this.IsAborting = true; |
|||
m_asyncQueryInfo.AbortQuery(); |
|||
} |
|||
} |
|||
|
|||
internal void QueueQueryData( Dispatcher dispatcher ) |
|||
{ |
|||
Debug.Assert( !this.IsDisposed ); |
|||
|
|||
Debug.Assert( m_asyncQueryInfo == null ); |
|||
|
|||
m_asyncQueryInfo = new AsyncQueryInfo( |
|||
dispatcher, |
|||
new Action<AsyncQueryInfo>( this.AsyncQueryInfo_BeginQueryItems ), |
|||
new Action<AsyncQueryInfo>( this.AsyncQueryInfo_AbortQueryItems ), |
|||
new Action<AsyncQueryInfo, object[]>( this.AsyncQueryInfo_EndQueryItems ), |
|||
new Action<AsyncQueryInfo>( this.AsyncQueryInfo_QueryErrorChanged ), |
|||
new Action<AsyncQueryInfo>( this.AsyncQueryInfo_BuiltInAbort ), |
|||
m_startDataIndex, |
|||
this.Count ); |
|||
|
|||
m_asyncQueryInfo.QueueQuery(); |
|||
} |
|||
|
|||
internal void EndQueryItems( AsyncQueryInfo asyncQueryInfo, object[] items ) |
|||
{ |
|||
Debug.Assert( !this.IsDisposed ); |
|||
|
|||
// This can occur when the user notify us that the QueryData is completed for an AsyncQueryInfo.StartIndex that refers to a Page which does exists
|
|||
// but that was removed, then re-created thus creating another asyncQueryInfo and queuing another QueryData.
|
|||
// The only way to get rid of this situation would be to keep a ref to the queued asyncQueryInfo even if we get rid of the page and re-link the same instance
|
|||
// to the newly created page. This optimization could be done in a future version. For now, let's return and the second asyncQueryInfo will take care of filling
|
|||
// the newly created page.
|
|||
if( m_asyncQueryInfo != asyncQueryInfo ) |
|||
{ |
|||
Debug.Assert( false ); |
|||
return; |
|||
} |
|||
|
|||
if( this.IsFilled ) |
|||
throw new InvalidOperationException( "An attempt was made to fill a virtual page that is already filled." ); |
|||
|
|||
if( items == null ) |
|||
throw new ArgumentNullException( "items" ); |
|||
|
|||
for( int i = 0; i < items.Length; i++ ) |
|||
{ |
|||
VirtualizedItemInfo virtualizedItemInfo = this[ i ]; |
|||
|
|||
Debug.Assert( virtualizedItemInfo.DataItem is EmptyDataItem ); |
|||
Debug.Assert( virtualizedItemInfo.Index == ( m_startDataIndex + i ) ); |
|||
|
|||
this[ i ].DataItem = items[ i ]; |
|||
} |
|||
|
|||
this.IsFilled = true; |
|||
Debug.WriteLineIf( VirtualPageManager.DebugDataVirtualization, "Page Filled - " + this.ToString() ); |
|||
} |
|||
|
|||
internal void QueueCommitData( Dispatcher dispatcher ) |
|||
{ |
|||
Debug.Assert( !this.IsDisposed ); |
|||
|
|||
int count = this.Count; |
|||
|
|||
List<VirtualizedItemInfo> dirtyItemInfoNotAlreadyPendingCommit = new List<VirtualizedItemInfo>( count ); |
|||
|
|||
for( int i = 0; i < count; i++ ) |
|||
{ |
|||
VirtualizedItemInfo virtualizedItemInfo = this[ i ]; |
|||
|
|||
if( ( virtualizedItemInfo.IsDirty ) && ( !this.IsAsyncCommitInfoQueuedForItem( virtualizedItemInfo.DataItem ) ) ) |
|||
{ |
|||
Debug.WriteLineIf( VirtualPageManager.DebugDataVirtualization, "QueueCommitData for page " + this.ToString() + " and index " + virtualizedItemInfo.Index ); |
|||
dirtyItemInfoNotAlreadyPendingCommit.Add( virtualizedItemInfo ); |
|||
} |
|||
} |
|||
|
|||
if( dirtyItemInfoNotAlreadyPendingCommit.Count > 0 ) |
|||
{ |
|||
AsyncCommitInfo asyncCommitInfo = new AsyncCommitInfo( |
|||
dispatcher, |
|||
new Action<AsyncCommitInfo>( this.AsyncCommitInfo_BeginCommitItems ), |
|||
new Action<AsyncCommitInfo>( this.AsyncCommitInfo_EndCommitItems ), |
|||
new Action<AsyncCommitInfo>( this.AsyncCommitInfo_CommitErrorChanged ), |
|||
dirtyItemInfoNotAlreadyPendingCommit.ToArray() ); |
|||
|
|||
m_asyncCommitInfoList.Add( asyncCommitInfo ); |
|||
asyncCommitInfo.BeginCommit(); |
|||
} |
|||
} |
|||
|
|||
internal bool IsAsyncCommitInfoQueuedForItem( object item ) |
|||
{ |
|||
int pendingAsyncCommitInfoCount = m_asyncCommitInfoList.Count; |
|||
|
|||
for( int i = 0; i < pendingAsyncCommitInfoCount; i++ ) |
|||
{ |
|||
VirtualizedItemInfo[] pendingCommitVirtualizedItemInfos = m_asyncCommitInfoList[ i ].VirtualizedItemInfos; |
|||
|
|||
foreach( VirtualizedItemInfo pendingCommitVirtualizedItemInfo in pendingCommitVirtualizedItemInfos ) |
|||
{ |
|||
if( pendingCommitVirtualizedItemInfo.DataItem == item ) |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
internal void EndCommitItems( AsyncCommitInfo asyncCommitInfo ) |
|||
{ |
|||
Debug.Assert( !this.IsDisposed ); |
|||
Debug.Assert( m_asyncCommitInfoList.Contains( asyncCommitInfo ) ); |
|||
|
|||
VirtualizedItemInfo[] commitedItemInfos = asyncCommitInfo.VirtualizedItemInfos; |
|||
|
|||
for( int i = 0; i < commitedItemInfos.Length; i++ ) |
|||
{ |
|||
commitedItemInfos[ i ].OldValues = null; |
|||
} |
|||
|
|||
m_asyncCommitInfoList.Remove( asyncCommitInfo ); |
|||
|
|||
asyncCommitInfo.Dispose(); |
|||
} |
|||
|
|||
internal void Restart() |
|||
{ |
|||
if( !this.IsRestarting ) |
|||
{ |
|||
Debug.WriteLineIf( VirtualPageManager.DebugDataVirtualization, "Restart VirtualPage requested for " + this.ToString() ); |
|||
this.IsRestarting = true; |
|||
this.ParentVirtualList.OnVirtualPageRestarting( this ); |
|||
} |
|||
|
|||
// The page has finished commiting or aborting
|
|||
if( ( !this.IsCommitPending ) && ( !this.IsAborting ) ) |
|||
{ |
|||
this.EndRestart(); |
|||
} |
|||
} |
|||
|
|||
internal void EndRestart() |
|||
{ |
|||
// VirtualPage will be disposed by the VirtualPageManager
|
|||
// when it removes the page from is m_pageNodeList
|
|||
Debug.WriteLineIf( VirtualPageManager.DebugDataVirtualization, "Restart VirtualPage completed for " + this.ToString() ); |
|||
this.IsRestarting = false; |
|||
this.ParentVirtualList.OnVirtualPageRestarted( this ); |
|||
} |
|||
|
|||
#endregion INTERNAL METHODS
|
|||
|
|||
#region PRIVATE METHODS
|
|||
|
|||
private int SourceIndexToPageEntryIndex( int sourceIndex ) |
|||
{ |
|||
if( ( this.Count != 0 ) && ( ( sourceIndex >= m_startDataIndex ) && ( sourceIndex <= this.EndDataIndex ) ) ) |
|||
return sourceIndex - m_startDataIndex; |
|||
|
|||
return -1; |
|||
} |
|||
|
|||
private bool ContainsItem( object item ) |
|||
{ |
|||
int count = this.Count; |
|||
|
|||
for( int i = 0; i < count; i++ ) |
|||
{ |
|||
if( this[ i ].DataItem == item ) |
|||
return true; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
#endregion PRIVATE METHODS
|
|||
|
|||
#region PRIVATE FIELDS
|
|||
|
|||
private BitVector32 m_flags; |
|||
|
|||
private int m_startDataIndex; |
|||
private int m_lockCount; |
|||
|
|||
private VirtualList m_parentVirtualList; |
|||
|
|||
private AsyncQueryInfo m_asyncQueryInfo; |
|||
private List<AsyncCommitInfo> m_asyncCommitInfoList; |
|||
|
|||
#endregion PRIVATE FIELDS
|
|||
|
|||
#region PRIVATE NESTED ENUMS
|
|||
|
|||
[Flags] |
|||
private enum VirtualItemPageFlags |
|||
{ |
|||
IsFilled = 1, |
|||
IsDisposed = 2, |
|||
} |
|||
|
|||
#endregion PRIVATE NESTED ENUMS
|
|||
|
|||
#region IDisposable Members
|
|||
|
|||
public void Dispose() |
|||
{ |
|||
|
|||
Debug.Assert( !this.IsDisposed ); |
|||
|
|||
Debug.Assert( ( m_asyncCommitInfoList != null ) && ( m_asyncCommitInfoList.Count == 0 ), "Some async commit are not completed while disposing VirtualPage" ); |
|||
|
|||
if( m_asyncQueryInfo != null ) |
|||
{ |
|||
// We must dispose the AsyncQueryInfo to be sure
|
|||
// it does not root this VirtualPage instance
|
|||
m_asyncQueryInfo.Dispose(); |
|||
m_asyncQueryInfo = null; |
|||
} |
|||
|
|||
this.Clear(); |
|||
m_parentVirtualList = null; |
|||
|
|||
this.IsDisposed = true; |
|||
|
|||
} |
|||
|
|||
#endregion
|
|||
} |
|||
} |
|||
@ -0,0 +1,867 @@ |
|||
/************************************************************************ |
|||
|
|||
Extended WPF Toolkit |
|||
|
|||
Copyright (C) 2010-2012 Xceed Software Inc. |
|||
|
|||
This program is provided to you under the terms of the Microsoft Public |
|||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
|||
|
|||
This program can be provided to you by Xceed Software Inc. under a |
|||
proprietary commercial license agreement for use in non-Open Source |
|||
projects. The commercial version of Extended WPF Toolkit also includes |
|||
priority technical support, commercial updates, and many additional |
|||
useful WPF controls if you license Xceed Business Suite for WPF. |
|||
|
|||
Visit http://xceed.com and follow @datagrid on Twitter.
|
|||
|
|||
**********************************************************************/ |
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Windows.Threading; |
|||
using System.Diagnostics; |
|||
using System.Collections.ObjectModel; |
|||
using System.Collections.Specialized; |
|||
|
|||
namespace Xceed.Wpf.DataGrid |
|||
{ |
|||
internal abstract class VirtualPageManager : IDisposable |
|||
{ |
|||
#region STATIC MEMBERS
|
|||
|
|||
internal static bool DebugDataVirtualization = false; |
|||
private const DispatcherPriority CommitDataPriority = DispatcherPriority.Input; |
|||
private const int EstimatedLockedPageCount = 3; |
|||
|
|||
#endregion STATIC MEMBERS
|
|||
|
|||
#region CONSTRUCTORS
|
|||
|
|||
public VirtualPageManager( Dispatcher dispatcher, |
|||
int pageSize, int maxRealizedItemCount, double preemptivePageQueryRatio ) |
|||
{ |
|||
if( dispatcher == null ) |
|||
throw new ArgumentNullException( "dispatcher" ); |
|||
|
|||
if( pageSize < 1 ) |
|||
throw new ArgumentOutOfRangeException( "pageSize", pageSize, "pageSize must be greater than zero." ); |
|||
|
|||
if( maxRealizedItemCount < pageSize ) |
|||
throw new ArgumentOutOfRangeException( "maxRealizedItemCount", maxRealizedItemCount, "maxRealizedItemCount must be greater than or equal to pageSize." ); |
|||
|
|||
m_managedLists = new List<VirtualList>(); |
|||
m_pageNodes = new LinkedList<VirtualPage>(); |
|||
|
|||
this.Dispatcher = dispatcher; |
|||
|
|||
m_pageSize = pageSize; |
|||
m_maxRealizedItemCount = maxRealizedItemCount; |
|||
|
|||
m_maxRemovablePageCount = ( m_maxRealizedItemCount / m_pageSize ); |
|||
|
|||
m_preemptivePageQueryRatio = preemptivePageQueryRatio; |
|||
|
|||
this.IsConnected = true; |
|||
} |
|||
|
|||
#endregion CONSTRUCTORS
|
|||
|
|||
#region DISPATCHER PROPERTY
|
|||
|
|||
public Dispatcher Dispatcher |
|||
{ |
|||
get; |
|||
private set; |
|||
} |
|||
|
|||
#endregion DISPATCHER PROPERTY
|
|||
|
|||
|
|||
#region PageSize Property
|
|||
|
|||
public int PageSize |
|||
{ |
|||
get |
|||
{ |
|||
return m_pageSize; |
|||
} |
|||
} |
|||
|
|||
#endregion PageSize Property
|
|||
|
|||
#region MaxRealizedItemCount Property
|
|||
|
|||
public int MaxRealizedItemCount |
|||
{ |
|||
get |
|||
{ |
|||
return m_maxRealizedItemCount; |
|||
} |
|||
} |
|||
|
|||
#endregion MaxRealizedItemCount Property
|
|||
|
|||
#region PreemptivePageQueryRatio Property
|
|||
|
|||
public double PreemptivePageQueryRatio |
|||
{ |
|||
get |
|||
{ |
|||
return m_preemptivePageQueryRatio; |
|||
} |
|||
set |
|||
{ |
|||
m_preemptivePageQueryRatio = value; |
|||
} |
|||
} |
|||
|
|||
#endregion PreemptivePageQueryRatio Property
|
|||
|
|||
#region ManagedLists Property
|
|||
|
|||
public ReadOnlyCollection<VirtualList> ManagedLists |
|||
{ |
|||
get |
|||
{ |
|||
if( m_readOnlyManagedLists == null ) |
|||
m_readOnlyManagedLists = new ReadOnlyCollection<VirtualList>( m_managedLists ); |
|||
|
|||
return m_readOnlyManagedLists; |
|||
} |
|||
} |
|||
|
|||
#endregion ManagedLists Property
|
|||
|
|||
#region IsDisposed Private Property
|
|||
|
|||
protected bool IsDisposed |
|||
{ |
|||
get |
|||
{ |
|||
return m_flags[ ( int )VirtualPageManagerFlags.IsDisposed ]; |
|||
} |
|||
private set |
|||
{ |
|||
m_flags[ ( int )VirtualPageManagerFlags.IsDisposed ] = value; |
|||
} |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region RestartingManager Private Property
|
|||
|
|||
private bool RestartingManager |
|||
{ |
|||
get |
|||
{ |
|||
return m_flags[ ( int )VirtualPageManagerFlags.RestartingManager ]; |
|||
} |
|||
set |
|||
{ |
|||
m_flags[ ( int )VirtualPageManagerFlags.RestartingManager ] = value; |
|||
} |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region ShouldRefreshAfterRestart Private Property
|
|||
|
|||
private bool ShouldRefreshAfterRestart |
|||
{ |
|||
get |
|||
{ |
|||
return m_flags[ ( int )VirtualPageManagerFlags.ShouldRefreshAfterRestart ]; |
|||
} |
|||
set |
|||
{ |
|||
m_flags[ ( int )VirtualPageManagerFlags.ShouldRefreshAfterRestart ] = value; |
|||
} |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
|
|||
#region DATA VIRTUALIZATION METHODS
|
|||
|
|||
protected virtual void OnVirtualPageManagerRestarting() |
|||
{ |
|||
} |
|||
|
|||
protected virtual void OnVirtualPageManagerRestarted( bool shouldRefresh ) |
|||
{ |
|||
} |
|||
|
|||
internal void QueueQueryData( VirtualPage page ) |
|||
{ |
|||
Debug.Assert( m_managedLists.Contains( page.ParentVirtualList ) ); |
|||
page.QueueQueryData( this.Dispatcher ); |
|||
} |
|||
|
|||
internal void QueueCommitData( VirtualPage page ) |
|||
{ |
|||
Debug.WriteLineIf( VirtualPageManager.DebugDataVirtualization, "QueueCommitData for page " + page.ToString() ); |
|||
Debug.Assert( m_managedLists.Contains( page.ParentVirtualList ) ); |
|||
Debug.Assert( page.IsFilled ); |
|||
Debug.Assert( page.IsDirty ); |
|||
|
|||
if( this.RestartingManager ) |
|||
this.ShouldRefreshAfterRestart = true; |
|||
|
|||
page.QueueCommitData( this.Dispatcher ); |
|||
} |
|||
|
|||
protected internal abstract void OnBuiltInAbort( VirtualPage virtualPage, AsyncQueryInfo queryInfo ); |
|||
|
|||
protected internal virtual int OnQueryItemCount( VirtualList virtualList ) |
|||
{ |
|||
return this.OnQueryItemCountCore( virtualList ); |
|||
} |
|||
|
|||
protected abstract int OnQueryItemCountCore( VirtualList virtualList ); |
|||
|
|||
protected internal abstract void OnQueryItems( VirtualPage page, AsyncQueryInfo queryInfo ); |
|||
|
|||
protected internal virtual void OnAbortQueryItems( VirtualPage page, AsyncQueryInfo queryInfo ) |
|||
{ |
|||
|
|||
} |
|||
|
|||
protected internal virtual void OnQueryItemsCompleted( VirtualPage page, AsyncQueryInfo queryInfo, object[] fetchedItems ) |
|||
{ |
|||
this.IncrementVersion(); |
|||
|
|||
page.ParentVirtualList.FillEmptyPage( queryInfo, fetchedItems ); |
|||
} |
|||
|
|||
protected internal virtual void OnCommitItems( VirtualPage page, AsyncCommitInfo commitInfo ) |
|||
{ |
|||
} |
|||
|
|||
protected internal virtual void OnCommitItemsCompleted( VirtualPage page, AsyncCommitInfo commitInfo ) |
|||
{ |
|||
page.ParentVirtualList.NotifyCommitComplete( commitInfo ); |
|||
} |
|||
|
|||
protected internal virtual void OnQueryErrorChanged( VirtualPage page, AsyncQueryInfo queryInfo ) |
|||
{ |
|||
} |
|||
|
|||
protected internal virtual void OnCommitErrorChanged( VirtualPage page, AsyncCommitInfo commitInfo ) |
|||
{ |
|||
} |
|||
|
|||
#endregion DATA VIRTUALIZATION METHODS
|
|||
|
|||
#region PAGE MANAGEMENT
|
|||
|
|||
internal List<LinkedListNode<VirtualPage>> GetUnlockedPendingFillNodes() |
|||
{ |
|||
List<LinkedListNode<VirtualPage>> unlockedPendingFillNodes = new List<LinkedListNode<VirtualPage>>(); |
|||
|
|||
LinkedListNode<VirtualPage> lastUnlockedPendingFillNode = m_pageNodes.Last; |
|||
|
|||
while( lastUnlockedPendingFillNode != null ) |
|||
{ |
|||
VirtualPage page = lastUnlockedPendingFillNode.Value; |
|||
|
|||
Debug.Assert( page != null ); |
|||
|
|||
if( ( !page.IsLocked ) && ( !page.IsFilled ) ) |
|||
{ |
|||
unlockedPendingFillNodes.Add( lastUnlockedPendingFillNode ); |
|||
} |
|||
|
|||
lastUnlockedPendingFillNode = lastUnlockedPendingFillNode.Previous; |
|||
} |
|||
|
|||
return unlockedPendingFillNodes; |
|||
} |
|||
|
|||
private LinkedListNode<VirtualPage> LastRemovable |
|||
{ |
|||
get |
|||
{ |
|||
LinkedListNode<VirtualPage> lastRemovableNode = m_pageNodes.Last; |
|||
|
|||
while( lastRemovableNode != null ) |
|||
{ |
|||
Debug.Assert( lastRemovableNode.Value != null ); |
|||
|
|||
VirtualPage page = lastRemovableNode.Value; |
|||
|
|||
if( page.IsRemovable ) |
|||
return lastRemovableNode; |
|||
|
|||
lastRemovableNode = lastRemovableNode.Previous; |
|||
} |
|||
|
|||
return lastRemovableNode; |
|||
} |
|||
} |
|||
|
|||
internal void CleanUpAndDisposeUnused() |
|||
{ |
|||
// Remove the less used unlocked pages. This will also ask to save it.
|
|||
//
|
|||
// Also remove all pending fill pages which are not locked wether or not we are under the max unlocked page count.
|
|||
// This is so the abort query event is raised so that the user can abort his fetching of data.
|
|||
|
|||
|
|||
// Start with the unlocked pending fill pages since it is mandatory to remove them all in order to abort the async
|
|||
// data fetching.
|
|||
// The first node in the list returned by the GetUnlockedPendingFillNodes method is the oldest one, so we can start
|
|||
// removing from the beginning of the returned list.
|
|||
List<LinkedListNode<VirtualPage>> unlockedPendingFillNodes = this.GetUnlockedPendingFillNodes(); |
|||
|
|||
int unlockedPendingFillCount = unlockedPendingFillNodes.Count; |
|||
|
|||
for( int i = 0; i < unlockedPendingFillCount; i++ ) |
|||
{ |
|||
this.QueueCommitDataOrAbortIfRequired( unlockedPendingFillNodes[ i ], true ); |
|||
} |
|||
|
|||
// Then, move on to removing the other unlocked pages not up for commit, if we are above the max item in memory limit.
|
|||
// There should not be any pending fill pages left which are not locked.
|
|||
|
|||
int removablePageItemCount = this.GetRemovablePageItemCount(); |
|||
|
|||
while( removablePageItemCount > m_maxRealizedItemCount ) |
|||
{ |
|||
LinkedListNode<VirtualPage> lastRemovable = this.LastRemovable; |
|||
|
|||
Debug.Assert( lastRemovable != null ); |
|||
|
|||
removablePageItemCount -= lastRemovable.Value.Count; |
|||
|
|||
this.QueueCommitDataOrAbortIfRequired( lastRemovable, true ); |
|||
} |
|||
} |
|||
|
|||
private int GetRemovablePageCount() |
|||
{ |
|||
int removablePageCount = 0; |
|||
|
|||
LinkedListNode<VirtualPage> pageNode = m_pageNodes.Last; |
|||
|
|||
while( pageNode != null ) |
|||
{ |
|||
VirtualPage page = pageNode.Value; |
|||
|
|||
Debug.Assert( page != null ); |
|||
|
|||
if( ( page != null ) && ( page.IsRemovable ) ) |
|||
removablePageCount++; |
|||
|
|||
pageNode = pageNode.Previous; |
|||
} |
|||
|
|||
return removablePageCount; |
|||
} |
|||
|
|||
private int GetRemovablePageItemCount() |
|||
{ |
|||
int removablePageItemCount = 0; |
|||
|
|||
LinkedListNode<VirtualPage> pageNode = m_pageNodes.Last; |
|||
|
|||
while( pageNode != null ) |
|||
{ |
|||
VirtualPage page = pageNode.Value; |
|||
|
|||
Debug.Assert( page != null ); |
|||
|
|||
if( ( page != null ) && ( page.IsRemovable ) ) |
|||
{ |
|||
removablePageItemCount += page.Count; |
|||
} |
|||
|
|||
pageNode = pageNode.Previous; |
|||
} |
|||
|
|||
return removablePageItemCount; |
|||
} |
|||
|
|||
private void QueueCommitDataOrAbortIfRequired( |
|||
LinkedListNode<VirtualPage> pageNode, |
|||
bool removeAfterOperation ) |
|||
{ |
|||
VirtualPage page = pageNode.Value; |
|||
|
|||
// Update the flag in case this page must be removed
|
|||
// after an abort or commit operation
|
|||
page.RemoveAfterOperation = removeAfterOperation; |
|||
|
|||
// The only circumstance when we should remove a page which is not removable is if we are restarting.
|
|||
Debug.Assert( ( page != null ) |
|||
&& ( !page.IsDisposed ) |
|||
&& ( ( page.IsRemovable ) || ( page.ParentVirtualList.IsRestarting ) ) ); |
|||
|
|||
if( page.IsDirty ) |
|||
{ |
|||
// Don't remove pages which contains modifications. We'll remove them from the book when they are committed, if they
|
|||
// aren't locked.
|
|||
this.QueueCommitData( page ); |
|||
} |
|||
else if( !page.IsFilled ) |
|||
{ |
|||
// The page is not filled, we must send abort
|
|||
// the QueryData for this page in case it was sent
|
|||
page.AbortQueryDataOperation(); |
|||
} |
|||
|
|||
// The page must be removed after operation
|
|||
// and it has nothing to commit and is not
|
|||
// currently aborting an operation. It is safe
|
|||
// to remove it
|
|||
if( removeAfterOperation |
|||
&& !page.IsCommitPending |
|||
&& !page.IsAborting ) |
|||
{ |
|||
this.RemovePage( page ); |
|||
} |
|||
} |
|||
|
|||
internal void RemovePage( VirtualPage page ) |
|||
{ |
|||
if( page.IsDisposed ) |
|||
return; |
|||
|
|||
Debug.Assert( page != null ); |
|||
//Debug.Assert( !page.IsRestarting );
|
|||
|
|||
Debug.Assert( !page.IsDirty ); |
|||
|
|||
// A filled page is being removed. Change the version.
|
|||
this.IncrementVersion(); |
|||
|
|||
// Update the table of content of the page's ParentVirtualList
|
|||
page.ParentVirtualList.TableOfContent.RemovePage( page ); |
|||
|
|||
m_pageNodes.Remove( page ); |
|||
|
|||
Debug.WriteLineIf( VirtualPageManager.DebugDataVirtualization, "Removed Page: " + page.ToString() ); |
|||
|
|||
// Dispose the page since it will never be reused
|
|||
page.Dispose(); |
|||
} |
|||
|
|||
internal void MovePageToFront( VirtualPage page ) |
|||
{ |
|||
// The further from the front a page is, the longer it has been since it was requested.
|
|||
Debug.Assert( page != null ); |
|||
|
|||
LinkedListNode<VirtualPage> firstNode = m_pageNodes.First; |
|||
|
|||
if( firstNode.Value != page ) |
|||
{ |
|||
LinkedListNode<VirtualPage> node = m_pageNodes.Find( page ); |
|||
|
|||
m_pageNodes.Remove( node ); |
|||
m_pageNodes.AddFirst( node ); |
|||
|
|||
Debug.WriteLineIf( VirtualPageManager.DebugDataVirtualization, "Moved To Front: Page " + page.ToString() ); |
|||
} |
|||
} |
|||
|
|||
internal void AddPage( VirtualPage page, PageInsertPosition insertPosition ) |
|||
{ |
|||
if( page == null ) |
|||
throw new ArgumentNullException( "page", "TODOOC: An internal error occured while paging data. Page cannot be null." ); |
|||
|
|||
// We call clean-up before the call to AddFirst since if we do
|
|||
// it afterward and the page is pending fill, we will remove it.
|
|||
this.CleanUpAndDisposeUnused(); |
|||
|
|||
if( insertPosition == PageInsertPosition.Front ) |
|||
{ |
|||
m_pageNodes.AddFirst( page ); |
|||
} |
|||
else |
|||
{ |
|||
m_pageNodes.AddLast( page ); |
|||
} |
|||
|
|||
Debug.WriteLineIf( VirtualPageManager.DebugDataVirtualization, "Added To " + ( ( insertPosition == PageInsertPosition.Front ) ? "Front" : "Back" ) + ": Page " + page.ToString() ); |
|||
} |
|||
|
|||
#endregion PAGE MANAGEMENT
|
|||
|
|||
#region RESTART MANAGEMENT
|
|||
|
|||
internal void Restart() |
|||
{ |
|||
if( this.RestartingManager ) |
|||
return; |
|||
|
|||
this.RestartingManager = true; |
|||
Debug.WriteLineIf( VirtualPageManager.DebugDataVirtualization, "VirtualPageManager (" + this.GetHashCode() + ") - Restarting all virtual Lists. " ); |
|||
|
|||
this.OnVirtualPageManagerRestarting(); |
|||
|
|||
if( m_managedLists.Count == 0 ) |
|||
{ |
|||
// No pages, restart is completed
|
|||
this.EndRestart(); |
|||
} |
|||
else |
|||
{ |
|||
m_restartingListsCount = m_managedLists.Count; |
|||
int managedListCount = m_managedLists.Count; |
|||
|
|||
// Restart all VirtualLists
|
|||
for( int i = managedListCount - 1; i >= 0; i-- ) |
|||
{ |
|||
VirtualList virtualList = m_managedLists[ i ]; |
|||
virtualList.Restart(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
protected virtual void EndRestart() |
|||
{ |
|||
this.RestartingManager = false; |
|||
Debug.WriteLineIf( VirtualPageManager.DebugDataVirtualization, "VirtualPageManager (" + this.GetHashCode() + ")- All virtual Lists restarted." ); |
|||
|
|||
this.OnVirtualPageManagerRestarted( this.ShouldRefreshAfterRestart ); |
|||
|
|||
this.ShouldRefreshAfterRestart = false; |
|||
} |
|||
|
|||
internal virtual void OnVirtualListRestarting( VirtualList virtualList ) |
|||
{ |
|||
Debug.Assert( m_managedLists.Contains( virtualList ) ); |
|||
|
|||
Debug.Assert( this.RestartingManager, "Until CollectionViewGroups can be virtualized, we should not be restarting a leaf list on its own." ); |
|||
} |
|||
|
|||
internal virtual void OnVirtualListRestarted( VirtualList virtualList ) |
|||
{ |
|||
Debug.Assert( m_managedLists.Contains( virtualList ) ); |
|||
|
|||
Debug.Assert( this.RestartingManager, "Until CollectionViewGroups can be virtualized, we should not be restarting a leaf list on its own." ); |
|||
|
|||
if( this.RestartingManager ) |
|||
m_restartingListsCount--; |
|||
|
|||
// Make sure that no page nodes belonging to this virtual
|
|||
// list are left in the linked list. Remove all remaining ones
|
|||
// since after the manager is restarted, its content is
|
|||
// completely cleared
|
|||
LinkedListNode<VirtualPage> pageNode = m_pageNodes.Last; |
|||
while( pageNode != null ) |
|||
{ |
|||
LinkedListNode<VirtualPage> previousNode = pageNode.Previous; |
|||
|
|||
if( pageNode.Value.ParentVirtualList == virtualList ) |
|||
throw new DataGridInternalException( "A VirtualPage was not remove from its parent VirtualList after it is restarted" ); |
|||
|
|||
pageNode = previousNode; |
|||
} |
|||
|
|||
this.IncrementVersion(); |
|||
|
|||
// If the manager is restarting, no page left and no more list restarting
|
|||
if( this.RestartingManager |
|||
&& ( m_pageNodes.Count == 0 ) |
|||
&& ( m_restartingListsCount == 0 ) ) |
|||
{ |
|||
this.EndRestart(); |
|||
} |
|||
} |
|||
|
|||
internal virtual void OnVirtualListPageRestarting( VirtualList virtualList, VirtualPage page ) |
|||
{ |
|||
Debug.Assert( m_managedLists.Contains( virtualList ) ); |
|||
|
|||
LinkedListNode<VirtualPage> pageNode = m_pageNodes.Find( page ); |
|||
|
|||
Debug.Assert( pageNode != null ); |
|||
|
|||
// RemovePageNode takes care of either raising the AbortQueryData event or aborting the QueryData Dispatcher Operation altogether.
|
|||
// It also takes care of raising the CommitVirtualData event for loaded pages which contains modified data.
|
|||
this.QueueCommitDataOrAbortIfRequired( pageNode, false ); |
|||
} |
|||
|
|||
internal virtual void OnVirtualListPageRestarted( VirtualList virtualList, VirtualPage page ) |
|||
{ |
|||
Debug.Assert( m_managedLists.Contains( virtualList ) ); |
|||
Debug.Assert( m_pageNodes.Contains( page ) ); |
|||
this.RemovePage( page ); |
|||
} |
|||
|
|||
#endregion RESTART MANAGEMENT
|
|||
|
|||
|
|||
#region INTERNAL PROPERTIES
|
|||
|
|||
internal int EstimatedTotalPageCount |
|||
{ |
|||
get |
|||
{ |
|||
return m_maxRemovablePageCount + VirtualPageManager.EstimatedLockedPageCount; |
|||
} |
|||
} |
|||
|
|||
internal int Version |
|||
{ |
|||
get |
|||
{ |
|||
return m_version; |
|||
} |
|||
} |
|||
|
|||
internal bool IsConnected |
|||
{ |
|||
get |
|||
{ |
|||
return m_flags[ ( int )VirtualPageManagerFlags.IsConnected ]; |
|||
} |
|||
private set |
|||
{ |
|||
m_flags[ ( int )VirtualPageManagerFlags.IsConnected ] = value; |
|||
} |
|||
} |
|||
|
|||
#endregion INTERNAL PROPERTIES
|
|||
|
|||
#region INTERNAL METHODS
|
|||
|
|||
internal void Disconnect() |
|||
{ |
|||
this.IsConnected = false; |
|||
} |
|||
|
|||
internal void ManageList( VirtualList virtualList ) |
|||
{ |
|||
Debug.Assert( !m_managedLists.Contains( virtualList ) ); |
|||
Debug.Assert( virtualList.VirtualPagingManager == null ); |
|||
|
|||
virtualList.VirtualPagingManager = this; |
|||
|
|||
this.m_managedLists.Add( virtualList ); |
|||
} |
|||
|
|||
internal bool IsAsyncCommitQueuedForItem( object item ) |
|||
{ |
|||
LinkedListNode<VirtualPage> pageNode = m_pageNodes.First; |
|||
|
|||
while( pageNode != null ) |
|||
{ |
|||
VirtualList virtualList = pageNode.Value.ParentVirtualList; |
|||
|
|||
Debug.Assert( m_managedLists.Contains( virtualList ) ); |
|||
|
|||
if( virtualList.IsAsyncCommitQueuedForItem( item ) ) |
|||
{ |
|||
Debug.Assert( !( item is EmptyDataItem ), "A commit operation should not have been queued for an EmptyDataItem." ); |
|||
return true; |
|||
} |
|||
|
|||
pageNode = pageNode.Next; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
internal bool IsItemDirty( object item ) |
|||
{ |
|||
LinkedListNode<VirtualPage> pageNode = m_pageNodes.First; |
|||
|
|||
while( pageNode != null ) |
|||
{ |
|||
VirtualList virtualList = pageNode.Value.ParentVirtualList; |
|||
|
|||
Debug.Assert( m_managedLists.Contains( virtualList ) ); |
|||
|
|||
if( virtualList.IsItemDirty( item ) ) |
|||
{ |
|||
Debug.Assert( !( item is EmptyDataItem ), "An EmptyDataItem should not have been flagged as dirty." ); |
|||
return true; |
|||
} |
|||
|
|||
pageNode = pageNode.Next; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
internal void SetCachedValuesForItem( object item, string[] names, object[] values ) |
|||
{ |
|||
LinkedListNode<VirtualPage> pageNode = m_pageNodes.First; |
|||
|
|||
while( pageNode != null ) |
|||
{ |
|||
VirtualList virtualList = pageNode.Value.ParentVirtualList; |
|||
|
|||
Debug.Assert( m_managedLists.Contains( virtualList ) ); |
|||
|
|||
int localIndex = virtualList.IndexOf( item ); |
|||
|
|||
if( localIndex != -1 ) |
|||
{ |
|||
virtualList.SetCachedValuesForItemAtIndex( localIndex, names, values ); |
|||
return; |
|||
} |
|||
|
|||
pageNode = pageNode.Next; |
|||
} |
|||
|
|||
throw new InvalidOperationException( "An attempt was made to begin the edit process on an unknown item." ); |
|||
} |
|||
|
|||
internal VirtualizedItemValueCollection GetCachedValuesForItem( object item ) |
|||
{ |
|||
LinkedListNode<VirtualPage> pageNode = m_pageNodes.First; |
|||
|
|||
while( pageNode != null ) |
|||
{ |
|||
VirtualList virtualList = pageNode.Value.ParentVirtualList; |
|||
|
|||
Debug.Assert( m_managedLists.Contains( virtualList ) ); |
|||
|
|||
int localIndex = virtualList.IndexOf( item ); |
|||
|
|||
if( localIndex != -1 ) |
|||
return virtualList.GetCachedValuesForItemAtIndex( localIndex ); |
|||
|
|||
pageNode = pageNode.Next; |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
internal void ClearCachedValuesForItem( object item ) |
|||
{ |
|||
LinkedListNode<VirtualPage> pageNode = m_pageNodes.First; |
|||
|
|||
while( pageNode != null ) |
|||
{ |
|||
VirtualList virtualList = pageNode.Value.ParentVirtualList; |
|||
|
|||
Debug.Assert( m_managedLists.Contains( virtualList ) ); |
|||
|
|||
int localIndex = virtualList.IndexOf( item ); |
|||
|
|||
if( localIndex != -1 ) |
|||
{ |
|||
virtualList.ClearCachedValuesForItemAtIndex( localIndex ); |
|||
return; |
|||
} |
|||
|
|||
pageNode = pageNode.Next; |
|||
} |
|||
|
|||
throw new InvalidOperationException( "An attempt was made to leave the edit process on an unknown item." ); |
|||
} |
|||
|
|||
internal void CommitAll() |
|||
{ |
|||
List<VirtualList> currentVirtualLists = new List<VirtualList>( m_pageNodes.Count ); |
|||
|
|||
LinkedListNode<VirtualPage> pageNode = m_pageNodes.First; |
|||
|
|||
// Scan all in memory pages to build a list of unique VirtualLists which currently have items loaded in memory.
|
|||
while( pageNode != null ) |
|||
{ |
|||
VirtualList virtualList = pageNode.Value.ParentVirtualList; |
|||
|
|||
Debug.Assert( m_managedLists.Contains( virtualList ) ); |
|||
|
|||
if( !currentVirtualLists.Contains( virtualList ) ) |
|||
currentVirtualLists.Add( virtualList ); |
|||
|
|||
pageNode = pageNode.Next; |
|||
} |
|||
|
|||
int currentVirtualListCount = currentVirtualLists.Count; |
|||
|
|||
for( int i = 0; i < currentVirtualListCount; i++ ) |
|||
{ |
|||
currentVirtualLists[ i ].CommitAll(); |
|||
} |
|||
} |
|||
|
|||
#endregion INTERNAL METHODS
|
|||
|
|||
#region PRIVATE METHODS
|
|||
|
|||
private void IncrementVersion() |
|||
{ |
|||
unchecked |
|||
{ |
|||
m_version++; |
|||
} |
|||
} |
|||
|
|||
#endregion PRIVATE METHODS
|
|||
|
|||
#region PRIVATE FIELDS
|
|||
|
|||
private int m_version; |
|||
private int m_restartingListsCount; |
|||
|
|||
private BitVector32 m_flags = new BitVector32(); |
|||
|
|||
private LinkedList<VirtualPage> m_pageNodes; |
|||
|
|||
private List<VirtualList> m_managedLists; |
|||
private ReadOnlyCollection<VirtualList> m_readOnlyManagedLists; |
|||
|
|||
private int m_pageSize; |
|||
private int m_maxRealizedItemCount; |
|||
private double m_preemptivePageQueryRatio; |
|||
private int m_maxRemovablePageCount; |
|||
|
|||
#endregion PRIVATE FIELDS
|
|||
|
|||
|
|||
#region PageInsertPosition private Enum
|
|||
|
|||
internal enum PageInsertPosition |
|||
{ |
|||
Front = 0, |
|||
Back = 1 |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region VirtualPageManagerFlags Enum
|
|||
|
|||
private enum VirtualPageManagerFlags |
|||
{ |
|||
RestartingManager = 1, |
|||
ShouldRefreshAfterRestart = 2, |
|||
IsDisposed = 4, |
|||
IsConnected = 8, |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region IDisposable Members
|
|||
|
|||
public void Dispose() |
|||
{ |
|||
this.DisposeCore(); |
|||
} |
|||
|
|||
protected virtual void DisposeCore() |
|||
{ |
|||
if( m_managedLists != null ) |
|||
{ |
|||
m_managedLists.Clear(); |
|||
} |
|||
|
|||
if( m_pageNodes != null ) |
|||
{ |
|||
m_pageNodes.Clear(); |
|||
} |
|||
|
|||
this.IsDisposed = true; |
|||
} |
|||
|
|||
#endregion
|
|||
} |
|||
} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue